| | |
| | |
| | |
| | |
| | |
| | |
| | import { |
| | type webpack, |
| | type SourceMapDevToolPluginOptions, |
| | ConcatenatedModule, |
| | makePathsAbsolute, |
| | ModuleFilenameHelpers, |
| | NormalModule, |
| | RuntimeGlobals, |
| | SourceMapDevToolModuleOptionsPlugin, |
| | } from 'next/dist/compiled/webpack/webpack' |
| | import type { RawSourceMap } from 'next/dist/compiled/source-map' |
| |
|
| | const cache = new WeakMap<webpack.sources.Source, webpack.sources.Source>() |
| |
|
| | const devtoolWarningMessage = `/* |
| | * ATTENTION: An "eval-source-map" devtool has been used. |
| | * This devtool is neither made for production nor for readable output files. |
| | * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. |
| | * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) |
| | * or disable the default devtool with "devtool: false". |
| | * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). |
| | */ |
| | ` |
| |
|
| | |
| | interface SourceMap extends RawSourceMap { |
| | ignoreList?: number[] |
| | version: number |
| | } |
| |
|
| | export interface EvalSourceMapDevToolPluginOptions |
| | extends SourceMapDevToolPluginOptions { |
| | |
| | shouldIgnorePath?: (modulePath: string) => boolean |
| | } |
| |
|
| | |
| | |
| | export default class EvalSourceMapDevToolPlugin { |
| | sourceMapComment: string |
| | moduleFilenameTemplate: NonNullable< |
| | EvalSourceMapDevToolPluginOptions['moduleFilenameTemplate'] |
| | > |
| | namespace: NonNullable<EvalSourceMapDevToolPluginOptions['namespace']> |
| | options: EvalSourceMapDevToolPluginOptions |
| | shouldIgnorePath: (modulePath: string) => boolean |
| |
|
| | |
| | |
| | |
| | constructor(inputOptions: EvalSourceMapDevToolPluginOptions) { |
| | let options: EvalSourceMapDevToolPluginOptions |
| | if (typeof inputOptions === 'string') { |
| | options = { |
| | append: inputOptions, |
| | } |
| | } else { |
| | options = inputOptions |
| | } |
| | this.sourceMapComment = |
| | options.append && typeof options.append !== 'function' |
| | ? options.append |
| | : '//# sourceURL=[module]\n//# sourceMappingURL=[url]' |
| | this.moduleFilenameTemplate = |
| | options.moduleFilenameTemplate || |
| | 'webpack://[namespace]/[resource-path]?[hash]' |
| | this.namespace = options.namespace || '' |
| | this.options = options |
| |
|
| | |
| | this.shouldIgnorePath = options.shouldIgnorePath ?? (() => false) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | apply(compiler: webpack.Compiler): void { |
| | const options = this.options |
| | compiler.hooks.compilation.tap( |
| | 'NextJSEvalSourceMapDevToolPlugin', |
| | (compilation) => { |
| | const { JavascriptModulesPlugin } = compiler.webpack.javascript |
| | const { RawSource, ConcatSource } = compiler.webpack.sources |
| |
|
| | const devtoolWarning = new RawSource(devtoolWarningMessage) |
| |
|
| | const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation) |
| |
|
| | new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation) |
| | const matchModule = ModuleFilenameHelpers.matchObject.bind( |
| | ModuleFilenameHelpers, |
| | options |
| | ) |
| |
|
| | hooks.renderModuleContent.tap( |
| | 'NextJSEvalSourceMapDevToolPlugin', |
| | (source, m, { chunk, runtimeTemplate, chunkGraph }) => { |
| | const cachedSource = cache.get(source) |
| | if (cachedSource !== undefined) { |
| | return cachedSource |
| | } |
| |
|
| | const result = ( |
| | r: webpack.sources.Source |
| | ): webpack.sources.Source => { |
| | cache.set(source, r) |
| | return r |
| | } |
| |
|
| | if (m instanceof NormalModule) { |
| | const module = m |
| | if (!matchModule(module.resource)) { |
| | return result(source) |
| | } |
| | } else if (m instanceof ConcatenatedModule) { |
| | const concatModule = m |
| | if (concatModule.rootModule instanceof NormalModule) { |
| | const module = concatModule.rootModule |
| | if (!matchModule(module.resource)) { |
| | return result(source) |
| | } |
| | } else { |
| | return result(source) |
| | } |
| | } else { |
| | return result(source) |
| | } |
| |
|
| | const namespace = compilation.getPath(this.namespace, { |
| | chunk, |
| | }) |
| | let sourceMap: SourceMap |
| | let content |
| | if (source.sourceAndMap) { |
| | const sourceAndMap = source.sourceAndMap(options) |
| | sourceMap = sourceAndMap.map as SourceMap |
| | content = sourceAndMap.source |
| | } else { |
| | sourceMap = source.map(options) as SourceMap |
| | content = source.source() |
| | } |
| | if (!sourceMap) { |
| | return result(source) |
| | } |
| |
|
| | |
| | sourceMap = { ...sourceMap } |
| | const context = compiler.options.context! |
| | const root = compiler.root |
| | const modules = sourceMap.sources.map((sourceMapSource) => { |
| | if (!sourceMapSource.startsWith('webpack://')) |
| | return sourceMapSource |
| | sourceMapSource = makePathsAbsolute( |
| | context, |
| | sourceMapSource.slice(10), |
| | root |
| | ) |
| | const module = compilation.findModule(sourceMapSource) |
| | return module || sourceMapSource |
| | }) |
| | let moduleFilenames = modules.map((module) => |
| | ModuleFilenameHelpers.createFilename( |
| | module, |
| | { |
| | moduleFilenameTemplate: this.moduleFilenameTemplate, |
| | namespace, |
| | }, |
| | { |
| | requestShortener: runtimeTemplate.requestShortener, |
| | chunkGraph, |
| | hashFunction: compilation.outputOptions.hashFunction!, |
| | } |
| | ) |
| | ) |
| | moduleFilenames = ModuleFilenameHelpers.replaceDuplicates( |
| | moduleFilenames, |
| | (filename, _i, n) => { |
| | for (let j = 0; j < n; j++) filename += '*' |
| | return filename |
| | } |
| | ) |
| | sourceMap.sources = moduleFilenames |
| | sourceMap.ignoreList = [] |
| | for (let index = 0; index < moduleFilenames.length; index++) { |
| | if (this.shouldIgnorePath(moduleFilenames[index])) { |
| | sourceMap.ignoreList.push(index) |
| | } |
| | } |
| | if (options.noSources) { |
| | sourceMap.sourcesContent = undefined |
| | } |
| | sourceMap.sourceRoot = options.sourceRoot || '' |
| | const moduleId = chunkGraph.getModuleId(m) |
| | if (moduleId) { |
| | sourceMap.file = |
| | typeof moduleId === 'number' ? `${moduleId}.js` : moduleId |
| | } |
| |
|
| | const footer = `${this.sourceMapComment.replace( |
| | /\[url\]/g, |
| | `data:application/json;charset=utf-8;base64,${Buffer.from( |
| | JSON.stringify(sourceMap), |
| | 'utf8' |
| | ).toString('base64')}` |
| | )}\n//# sourceURL=webpack-internal:///${moduleId}\n` |
| |
|
| | return result( |
| | new RawSource( |
| | `eval(${ |
| | compilation.outputOptions.trustedTypes |
| | ? `${RuntimeGlobals.createScript}(${JSON.stringify( |
| | content + footer |
| | )})` |
| | : JSON.stringify(content + footer) |
| | });` |
| | ) |
| | ) |
| | } |
| | ) |
| | hooks.inlineInRuntimeBailout.tap( |
| | 'EvalDevToolModulePlugin', |
| | () => 'the eval-source-map devtool is used.' |
| | ) |
| | hooks.render.tap('EvalSourceMapDevToolPlugin', (source, context) => { |
| | if ( |
| | context.chunk.id === 'webpack' || |
| | context.chunk.id === 'webpack-runtime' |
| | ) { |
| | const sourceURL = new URL( |
| | 'webpack-internal://nextjs/' + context.chunk.id + '.js' |
| | ) |
| | |
| | |
| | |
| | |
| | |
| | const sourceMappingURL = new URL( |
| | 'data:application/json;charset=utf-8;base64,' + |
| | Buffer.from( |
| | JSON.stringify({ |
| | version: 3, |
| | ignoreList: [0], |
| | |
| | mappings: 'AAAA', |
| | sources: [ |
| | |
| | sourceURL.toString(), |
| | ], |
| | sourcesContent: [ |
| | '' + |
| | '// This source was generated by Next.js based off of the generated Webpack runtime.\n' + |
| | '// The mappings are incorrect.\n' + |
| | '// To get the correct line/column mappings, turn off sourcemaps in your debugger.\n' + |
| | '\n' + |
| | source.source(), |
| | ], |
| | }) |
| | ).toString('base64') |
| | ) |
| |
|
| | return new ConcatSource( |
| | source, |
| | new RawSource( |
| | '\n//# sourceMappingURL=' + |
| | sourceMappingURL + |
| | |
| | |
| | |
| | '\n' |
| | ) |
| | |
| | |
| | |
| | ) |
| | } else { |
| | return new ConcatSource(devtoolWarning, source) |
| | } |
| | }) |
| | hooks.chunkHash.tap('EvalSourceMapDevToolPlugin', (_chunk, hash) => { |
| | hash.update('EvalSourceMapDevToolPlugin') |
| | hash.update('2') |
| | }) |
| | if (compilation.outputOptions.trustedTypes) { |
| | compilation.hooks.additionalModuleRuntimeRequirements.tap( |
| | 'EvalSourceMapDevToolPlugin', |
| | (_module, set, _context) => { |
| | set.add(RuntimeGlobals.createScript) |
| | } |
| | ) |
| | } |
| | } |
| | ) |
| | } |
| | } |
| |
|