webpack
Version:
Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.
156 lines (144 loc) • 5.29 kB
JavaScript
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
;
const { ConcatSource, RawSource } = require("webpack-sources");
const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
const RuntimeGlobals = require("../runtime/RuntimeGlobals");
const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
/** @import { Source } from "webpack-sources" */
/**
* @import {
* DevtoolNamespace,
* DevtoolModuleFilenameTemplate
* } from "../../declarations/WebpackOptions"
*/
/** @import Compiler from "../Compiler" */
/** @type {WeakMap<Source, Source>} */
const cache = new WeakMap();
const CLEAR_SOURCE_COPIES = { maps: false, source: true };
const devtoolWarning = new RawSource(`/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file 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/).
*/
`);
/**
* Defines the eval dev tool module plugin options type used by this module.
* @typedef {object} EvalDevToolModulePluginOptions
* @property {DevtoolNamespace=} namespace namespace
* @property {string=} sourceUrlComment source url comment
* @property {DevtoolModuleFilenameTemplate=} moduleFilenameTemplate module filename template
*/
const PLUGIN_NAME = "EvalDevToolModulePlugin";
class EvalDevToolModulePlugin {
/**
* Creates an instance of EvalDevToolModulePlugin.
* @param {EvalDevToolModulePluginOptions=} options options
*/
constructor(options = {}) {
/** @type {DevtoolNamespace} */
this.namespace = options.namespace || "";
/** @type {string} */
this.sourceUrlComment = options.sourceUrlComment || "\n//# sourceURL=[url]";
/** @type {DevtoolModuleFilenameTemplate} */
this.moduleFilenameTemplate =
options.moduleFilenameTemplate ||
"webpack://[namespace]/[resourcePath]?[loaders]";
}
/**
* Applies the plugin by registering its hooks on the compiler.
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
// Shared across this compilation's modules, so a source reachable from
// several chunks is walked once rather than once per chunk.
/** @type {WeakSet<Source>} */
const clearCacheVisited = new WeakSet();
hooks.renderModuleContent.tap(
PLUGIN_NAME,
(source, module, { chunk, runtimeTemplate, chunkGraph }) => {
const cacheEntry = cache.get(source);
if (cacheEntry !== undefined) return cacheEntry;
if (module.is("external")) {
cache.set(source, source);
return source;
}
const content = source.source();
const namespace = compilation.getPath(this.namespace, {
chunk
});
const str = ModuleFilenameHelpers.createFilename(
module,
{
moduleFilenameTemplate: this.moduleFilenameTemplate,
namespace
},
{
requestShortener: runtimeTemplate.requestShortener,
chunkGraph,
hashFunction: compilation.outputOptions.hashFunction
}
);
const footer = `\n${this.sourceUrlComment.replace(
/\[url\]/g,
encodeURI(str)
.replace(/%2F/g, "/")
.replace(/%20/g, "_")
.replace(/%5E/g, "^")
.replace(/%5C/g, "\\")
.replace(/^\//, "")
)}`;
const result = new RawSource(
`eval(${
compilation.outputOptions.trustedTypes
? `${RuntimeGlobals.createScript}(${JSON.stringify(
`{${content + footer}\n}`
)})`
: JSON.stringify(`{${content + footer}\n}`)
});`
);
cache.set(source, result);
// WHY: reading `source.source()` above left this source holding the
// flattened module text, which nothing reads again — the wrapper
// replaces it in rendering, and hashing ran before this. Clearing is
// a memory hint, so the worst case is re-flattening on a later read.
// Feature-detected, since `clearCache` landed in webpack-sources 3.5
// and a third-party plugin may hand us an older `Source`.
if (typeof source.clearCache === "function") {
source.clearCache(CLEAR_SOURCE_COPIES, clearCacheVisited);
}
return result;
}
);
hooks.inlineInRuntimeBailout.tap(
PLUGIN_NAME,
() => "the eval devtool is used."
);
hooks.render.tap(
PLUGIN_NAME,
(source) => new ConcatSource(devtoolWarning, source)
);
hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash) => {
hash.update(PLUGIN_NAME);
hash.update("2");
});
if (compilation.outputOptions.trustedTypes) {
compilation.hooks.additionalModuleRuntimeRequirements.tap(
PLUGIN_NAME,
(module, set, _context) => {
set.add(RuntimeGlobals.createScript);
}
);
}
});
}
}
module.exports = EvalDevToolModulePlugin;