refactor Module.source() and Module.getRuntimeRequirements() into Module.codeGeneration

add code generation phase to Compilation
add `output.iife` options to remove iife wrapper
add `experiments.outputModule` which enabled `output.module`
add `output.module` which sets defaults to `output.iife: false`, `output.libraryTarget: "module"`, `output.jsonpScriptType: "module"`, `terserOptions.module: true`
add `output.module` example
improve runtime requirements needed by ConcatenatedModule
add entry inlining, which inlines entry module code into runtime scope (only when safe)
make whole bundle strict when all modules are strict
This commit is contained in:
Tobias Koppers 2019-10-08 22:29:46 +02:00
parent f6e4dc69c7
commit ddc3dae0e6
47 changed files with 1327 additions and 764 deletions

9
declarations.d.ts vendored
View File

@ -7,6 +7,15 @@ declare namespace NodeJS {
}
}
// TODO remove when https://github.com/DefinitelyTyped/DefinitelyTyped/pull/38753 is merged
declare module "util" {
function deprecate<T extends Function>(
fn: T,
message: string,
code?: string
): T;
}
declare module "neo-async" {
interface QueueObject<T, E> {
push(item: T): void;

View File

@ -552,6 +552,10 @@ export interface Experiments {
* Support .mjs files as way to define strict ESM file (node.js)
*/
mjs?: boolean;
/**
* Allow outputing javascript files as module source type
*/
outputModule?: boolean;
/**
* Support WebAssembly as synchronous EcmaScript Module (outdated)
*/
@ -1237,6 +1241,10 @@ export interface OutputOptions {
* The filename of the Hot Update Main File. It is inside the `output.path` directory.
*/
hotUpdateMainFilename?: string;
/**
* Wrap javascript code into IIFEs to avoid leaking into global scope.
*/
iife?: boolean;
/**
* The JSONP function used by webpack for async loading of chunks.
*/
@ -1258,6 +1266,7 @@ export interface OutputOptions {
*/
libraryTarget?:
| "var"
| "module"
| "assign"
| "this"
| "window"
@ -1272,6 +1281,10 @@ export interface OutputOptions {
| "umd2"
| "jsonp"
| "system";
/**
* Output javascript files as module source type.
*/
module?: boolean;
/**
* The output directory as **absolute path** (required).
*/

117
examples/module/README.md Normal file
View File

@ -0,0 +1,117 @@
# example.js
```javascript
import { increment as inc, value } from "./counter";
import { resetCounter, print } from "./methods";
print(value);
inc();
inc();
inc();
print(value);
resetCounter();
print(value);
```
# methods.js
```javascript
export { reset as resetCounter } from "./counter";
export const print = value => console.log(value);
```
# counter.js
```javascript
export let value = 0;
export function increment() {
value++;
}
export function decrement() {
value--;
}
export function reset() {
value = 0;
}
```
# dist/output.js
```javascript
/******/ "use strict";
/*!********************************!*\
!*** ./example.js + 2 modules ***!
\********************************/
/*! exports [not provided] [unused] */
/*! runtime requirements: supports-symbols-deconflicting */
// CONCATENATED MODULE: ./counter.js
let value = 0;
function increment() {
value++;
}
function decrement() {
value--;
}
function counter_reset() {
value = 0;
}
// CONCATENATED MODULE: ./methods.js
const print = value => console.log(value);
// CONCATENATED MODULE: ./example.js
print(value);
increment();
increment();
increment();
print(value);
counter_reset();
print(value);
```
# dist/output.js (production)
```javascript
let o=0;function n(){o++}const c=o=>console.log(o);c(o),n(),n(),n(),c(o),c(o=0);
```
# Info
## Unoptimized
```
Hash: 0a1b2c3d4e5f6a7b8c9d
Version: webpack 5.0.0-alpha.30
Asset Size Chunks Chunk Names
output.js 621 bytes {0} [emitted] main
Entrypoint main = output.js
chunk {0} output.js (main) 429 bytes [entry] [rendered]
> ./example.js main
[0] ./example.js + 2 modules 429 bytes {0} [built]
[no exports]
[no exports used]
entry ./example.js main
used a library export
```
## Production mode
```
Hash: 0a1b2c3d4e5f6a7b8c9d
Version: webpack 5.0.0-alpha.30
Asset Size Chunks Chunk Names
output.js 80 bytes {179} [emitted] main
Entrypoint main = output.js
chunk {179} output.js (main) 429 bytes [entry] [rendered]
> ./example.js main
[291] ./example.js + 2 modules 429 bytes {179} [built]
[no exports]
[no exports used]
entry ./example.js main
used a library export
```

View File

@ -0,0 +1 @@
export var answer = 42;

1
examples/module/build.js Normal file
View File

@ -0,0 +1 @@
require("../build-common");

View File

@ -0,0 +1,10 @@
export let value = 0;
export function increment() {
value++;
}
export function decrement() {
value--;
}
export function reset() {
value = 0;
}

View File

@ -0,0 +1,9 @@
import { increment as inc, value } from "./counter";
import { resetCounter, print } from "./methods";
print(value);
inc();
inc();
inc();
print(value);
resetCounter();
print(value);

View File

@ -0,0 +1,3 @@
export { reset as resetCounter } from "./counter";
export const print = value => console.log(value);

View File

@ -0,0 +1,43 @@
# example.js
```javascript
_{{example.js}}_
```
# methods.js
```javascript
_{{methods.js}}_
```
# counter.js
```javascript
_{{counter.js}}_
```
# dist/output.js
```javascript
_{{dist/output.js}}_
```
# dist/output.js (production)
```javascript
_{{production:dist/output.js}}_
```
# Info
## Unoptimized
```
_{{stdout}}_
```
## Production mode
```
_{{production:stdout}}_
```

View File

@ -0,0 +1,12 @@
module.exports = {
output: {
module: true
},
optimization: {
usedExports: true,
concatenateModules: true
},
experiments: {
outputModule: true
}
};

View File

@ -0,0 +1,31 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const WebpackError = require("./WebpackError");
/** @typedef {import("./Module")} Module */
class CodeGenerationError extends WebpackError {
/**
* Create a new CodeGenerationError
* @param {Module} module related module
* @param {Error} error Original error
*/
constructor(module, error) {
super();
this.name = "CodeGenerationError";
this.error = error;
this.message = error.message;
this.details = error.stack;
this.module = module;
Error.captureStackTrace(this, this.constructor);
}
}
module.exports = CodeGenerationError;

View File

@ -20,6 +20,7 @@ const ChunkGraph = require("./ChunkGraph");
const ChunkGroup = require("./ChunkGroup");
const ChunkRenderError = require("./ChunkRenderError");
const ChunkTemplate = require("./ChunkTemplate");
const CodeGenerationError = require("./CodeGenerationError");
const DependencyTemplates = require("./DependencyTemplates");
const Entrypoint = require("./Entrypoint");
const ErrorHelpers = require("./ErrorHelpers");
@ -65,6 +66,7 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
/** @typedef {import("./DependencyTemplate")} DependencyTemplate */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./ModuleFactory")} ModuleFactory */
/** @typedef {import("./RuntimeModule")} RuntimeModule */
/** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */
@ -372,6 +374,11 @@ class Compilation {
/** @type {SyncHook<[]>} */
afterModuleHash: new SyncHook([]),
/** @type {SyncHook<[]>} */
beforeCodeGeneration: new SyncHook([]),
/** @type {SyncHook<[]>} */
afterCodeGeneration: new SyncHook([]),
/** @type {SyncHook<[]>} */
beforeRuntimeRequirements: new SyncHook([]),
/** @type {SyncHook<[]>} */
@ -516,6 +523,8 @@ class Compilation {
this.moduleGraph = new ModuleGraph();
this.chunkGraph = undefined;
/** @type {Map<Module, CodeGenerationResult>} */
this.codeGenerationResults = undefined;
/** @type {AsyncQueue<TODO, TODO, Module>} */
this.factorizeQueue = new AsyncQueue({
@ -1453,6 +1462,10 @@ class Compilation {
this.createModuleHashes();
this.hooks.afterModuleHash.call();
this.hooks.beforeCodeGeneration.call();
this.codeGenerationResults = this.codeGeneration();
this.hooks.afterCodeGeneration.call();
this.hooks.beforeRuntimeRequirements.call();
this.processRuntimeRequirements(this.entrypoints.values());
this.hooks.afterRuntimeRequirements.call();
@ -1563,30 +1576,51 @@ class Compilation {
}
}
codeGeneration() {
const {
chunkGraph,
moduleGraph,
dependencyTemplates,
runtimeTemplate
} = this;
const results = new Map();
for (const module of this.modules) {
if (chunkGraph.getNumberOfModuleChunks(module) > 0) {
try {
const r = module.codeGeneration({
chunkGraph,
moduleGraph,
dependencyTemplates,
runtimeTemplate
});
results.set(module, r);
} catch (err) {
this.errors.push(new CodeGenerationError(module, err));
results.set(module, {
sources: new Map(),
runtimeRequirements: null
});
}
}
}
return results;
}
/**
* @param {Iterable<Entrypoint>} entrypoints the entrypoints
* @returns {void}
*/
processRuntimeRequirements(entrypoints) {
const {
chunkGraph,
moduleGraph,
runtimeTemplate,
dependencyTemplates
} = this;
const { chunkGraph } = this;
const additionalModuleRuntimeRequirements = /** @type {TODO} */ (this.hooks
.additionalModuleRuntimeRequirements);
const runtimeRequirementInModule = this.hooks.runtimeRequirementInModule;
for (const module of this.modules) {
if (chunkGraph.getNumberOfModuleChunks(module) > 0) {
const runtimeRequirements = module.getRuntimeRequirements({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
});
let set;
const runtimeRequirements = this.codeGenerationResults.get(module)
.runtimeRequirements;
if (runtimeRequirements) {
set = new Set(runtimeRequirements);
} else if (additionalModuleRuntimeRequirements.isUsed()) {
@ -2201,6 +2235,7 @@ class Compilation {
hash: this.hash,
fullHash: this.fullHash,
outputOptions,
codeGenerationResults: this.codeGenerationResults,
moduleTemplates: this.moduleTemplates,
dependencyTemplates: this.dependencyTemplates,
chunkGraph: this.chunkGraph,

View File

@ -26,9 +26,10 @@ const makeSerializable = require("./util/makeSerializable");
/** @typedef {import("./ChunkGroup").RawChunkGroupOptions} RawChunkGroupOptions */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */
/** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
/** @typedef {import("./Module").SourceContext} SourceContext */
/** @typedef {import("./ModuleGraph")} ModuleGraph */
/** @typedef {import("./RequestShortener")} RequestShortener */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
@ -882,7 +883,7 @@ module.exports = webpackEmptyAsyncContext;`;
/**
* @param {string} asyncMode module mode
* @param {SourceContext} sourceContext context info
* @param {CodeGenerationContext} context context info
* @returns {string} the source code
*/
getSourceString(asyncMode, { runtimeTemplate, chunkGraph }) {
@ -943,21 +944,16 @@ module.exports = webpackEmptyAsyncContext;`;
}
/**
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
* @param {CodeGenerationContext} context context for code generation
* @returns {CodeGenerationResult} result
*/
source(sourceContext) {
return this.getSource(
this.getSourceString(this.options.mode, sourceContext)
codeGeneration(context) {
const { chunkGraph } = context;
const sources = new Map();
sources.set(
"javascript",
this.getSource(this.getSourceString(this.options.mode, context))
);
}
/**
* Get a list of runtime requirements
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements({ chunkGraph }) {
const set = [];
const allDeps = /** @type {ContextElementDependency[]} */ (this.dependencies.concat(
this.blocks.map(b => b.dependencies[0])
@ -978,7 +974,10 @@ module.exports = webpackEmptyAsyncContext;`;
set.push(RuntimeGlobals.createFakeNamespaceObject);
}
}
return set;
return {
sources,
runtimeRequirements: set
};
}
/**

View File

@ -16,6 +16,8 @@ const StaticExportsDependency = require("./dependencies/StaticExportsDependency"
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./LibManifestPlugin").ManifestModuleData} ManifestModuleData */
/** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */
/** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
/** @typedef {import("./Module").SourceContext} SourceContext */
@ -110,10 +112,10 @@ class DelegatedModule extends Module {
}
/**
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
* @param {CodeGenerationContext} context context for code generation
* @returns {CodeGenerationResult} result
*/
source({ runtimeTemplate, moduleGraph, chunkGraph }) {
codeGeneration({ runtimeTemplate, moduleGraph, chunkGraph }) {
const dep = /** @type {DelegatedSourceDependency} */ (this.dependencies[0]);
const sourceModule = moduleGraph.getModule(dep);
let str;
@ -142,20 +144,17 @@ class DelegatedModule extends Module {
str += ";";
}
const sources = new Map();
if (this.useSourceMap) {
return new OriginalSource(str, this.identifier());
sources.set("javascript", new OriginalSource(str, this.identifier()));
} else {
return new RawSource(str);
sources.set("javascript", new RawSource(str));
}
}
/**
* Get a list of runtime requirements
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements(context) {
return [RuntimeGlobals.module, RuntimeGlobals.require];
return {
sources,
runtimeRequirements: [RuntimeGlobals.module, RuntimeGlobals.require]
};
}
/**

View File

@ -13,6 +13,8 @@ const RuntimeGlobals = require("./RuntimeGlobals");
/** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
/** @typedef {import("./Module").SourceContext} SourceContext */
/** @typedef {import("./RequestShortener")} RequestShortener */
@ -68,20 +70,19 @@ class DllModule extends Module {
}
/**
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
* @param {CodeGenerationContext} context context for code generation
* @returns {CodeGenerationResult} result
*/
source(sourceContext) {
return new RawSource("module.exports = __webpack_require__;");
}
/**
* Get a list of runtime requirements
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements(context) {
return [RuntimeGlobals.require, RuntimeGlobals.module];
codeGeneration(context) {
const sources = new Map();
sources.set(
"javascript",
new RawSource("module.exports = __webpack_require__;")
);
return {
sources,
runtimeRequirements: [RuntimeGlobals.require, RuntimeGlobals.module]
};
}
/**

View File

@ -7,6 +7,7 @@
const { ConcatSource } = require("webpack-sources");
const JavascriptModulesPlugin = require("./JavascriptModulesPlugin");
const { UsageState } = require("./ModuleGraph");
/** @typedef {import("./Compiler")} Compiler */
@ -21,9 +22,11 @@ const accessorToObjectAccess = accessor => {
class ExportPropertyTemplatePlugin {
/**
* @param {string|string[]} property the name of the property to export
* @param {string} explanation an explanation why this property is used
*/
constructor(property) {
constructor(property, explanation) {
this.property = property;
this.explanation = explanation;
}
/**
@ -34,6 +37,27 @@ class ExportPropertyTemplatePlugin {
compiler.hooks.thisCompilation.tap(
"ExportPropertyTemplatePlugin",
compilation => {
const moduleGraph = compilation.moduleGraph;
compilation.hooks.seal.tap("ExportPropertyTemplatePlugin", () => {
for (const deps of compilation.entryDependencies.values()) {
const dep = deps[deps.length - 1];
if (dep) {
const module = moduleGraph.getModule(dep);
if (module) {
const exportsInfo = moduleGraph.getExportInfo(
module,
Array.isArray(this.property)
? this.property[0]
: this.property
);
exportsInfo.used = UsageState.Used;
exportsInfo.canMangleUse = false;
moduleGraph.addExtraReason(module, this.explanation);
}
}
}
});
const hooks = JavascriptModulesPlugin.getCompilationHooks(compilation);
hooks.renderWithEntry.tap(

View File

@ -16,9 +16,10 @@ const makeSerializable = require("./util/makeSerializable");
/** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */
/** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
/** @typedef {import("./Module").SourceContext} SourceContext */
/** @typedef {import("./RequestShortener")} RequestShortener */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("./WebpackError")} WebpackError */
@ -192,7 +193,9 @@ class ExternalModule extends Module {
*/
build(options, compilation, resolver, fs, callback) {
this.buildMeta = {};
this.buildInfo = {};
this.buildInfo = {
strict: true
};
callback();
}
@ -235,20 +238,27 @@ class ExternalModule extends Module {
}
/**
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
* @param {CodeGenerationContext} context context for code generation
* @returns {CodeGenerationResult} result
*/
source({ runtimeTemplate, moduleGraph, chunkGraph }) {
codeGeneration({ runtimeTemplate, moduleGraph, chunkGraph }) {
const sourceString = this.getSourceString(
runtimeTemplate,
moduleGraph,
chunkGraph
);
const sources = new Map();
if (this.useSourceMap) {
return new OriginalSource(sourceString, this.identifier());
sources.set(
"javascript",
new OriginalSource(sourceString, this.identifier())
);
} else {
return new RawSource(sourceString);
sources.set("javascript", new RawSource(sourceString));
}
return { sources, runtimeRequirements: [RuntimeGlobals.module] };
}
/**
@ -259,15 +269,6 @@ class ExternalModule extends Module {
return 42;
}
/**
* Get a list of runtime requirements
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements(context) {
return [RuntimeGlobals.module];
}
/**
* @param {Hash} hash the hash used to track dependencies
* @param {ChunkGraph} chunkGraph the chunk graph

View File

@ -7,7 +7,7 @@
const { UsageState } = require("./ModuleGraph");
const { STAGE_DEFAULT } = require("./OptimizationStages");
const { NS_OBJECT_IMPORTED } = require("./dependencies/DependencyReference");
const { NO_IMPORTED_NAMES } = require("./dependencies/DependencyReference");
const Queue = require("./util/Queue");
/** @typedef {import("./Compiler")} Compiler */
@ -143,7 +143,8 @@ class FlagDependencyUsagePlugin {
for (const dep of deps) {
const module = moduleGraph.getModule(dep);
if (module) {
processModule(module, NS_OBJECT_IMPORTED);
processModule(module, NO_IMPORTED_NAMES);
queue.enqueue(module);
}
}
}

View File

@ -0,0 +1,46 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
/** @typedef {import("./Compiler")} Compiler */
class FlagEntryExportAsUsedPlugin {
constructor(nsObjectUsed, explanation) {
this.nsObjectUsed = nsObjectUsed;
this.explanation = explanation;
}
/**
* @param {Compiler} compiler webpack compiler
* @returns {void}
*/
apply(compiler) {
compiler.hooks.thisCompilation.tap(
"FlagEntryExportAsUsedPlugin",
compilation => {
const moduleGraph = compilation.moduleGraph;
compilation.hooks.seal.tap("FlagEntryExportAsUsedPlugin", () => {
for (const deps of compilation.entryDependencies.values()) {
for (const dep of deps) {
const module = moduleGraph.getModule(dep);
if (module) {
const exportsInfo = moduleGraph.getExportsInfo(module);
if (this.nsObjectUsed) {
exportsInfo.setUsedInUnknownWay();
} else {
exportsInfo.setAllKnownExportsUsed();
}
moduleGraph.addExtraReason(module, this.explanation);
}
}
}
});
}
);
}
}
module.exports = FlagEntryExportAsUsedPlugin;

View File

@ -343,6 +343,7 @@ class HotModuleReplacementPlugin {
outputOptions: compilation.outputOptions,
moduleTemplates: compilation.moduleTemplates,
dependencyTemplates: compilation.dependencyTemplates,
codeGenerationResults: compilation.codeGenerationResults,
runtimeTemplate: compilation.runtimeTemplate,
moduleGraph: compilation.moduleGraph,
chunkGraph

View File

@ -9,7 +9,8 @@ const { SyncWaterfallHook, SyncHook } = require("tapable");
const {
ConcatSource,
OriginalSource,
PrefixSource
PrefixSource,
RawSource
} = require("webpack-sources");
const Compilation = require("./Compilation");
const { tryRunOrWebpackError } = require("./HookWebpackError");
@ -28,6 +29,7 @@ const createHash = require("./util/createHash");
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./ModuleGraph")} ModuleGraph */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("./util/Hash")} Hash */
@ -55,6 +57,7 @@ const chunkHasJs = (chunk, chunkGraph) => {
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {Map<Module, CodeGenerationResult>} codeGenerationResults results of code generation
*/
/**
@ -64,6 +67,7 @@ const chunkHasJs = (chunk, chunkGraph) => {
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {Map<Module, CodeGenerationResult>} codeGenerationResults results of code generation
* @property {string} hash hash to be used for render call
*/
@ -131,6 +135,10 @@ class JavascriptModulesPlugin {
return hooks;
}
constructor(options = {}) {
this.options = options;
}
/**
* @param {Compiler} compiler webpack compiler
* @returns {void}
@ -174,12 +182,14 @@ class JavascriptModulesPlugin {
"JavascriptModulesPlugin",
(result, options) => {
const {
hash,
chunk,
chunkGraph,
moduleGraph,
runtimeTemplate,
dependencyTemplates,
outputOptions
outputOptions,
codeGenerationResults
} = options;
const hotUpdateChunk =
@ -197,13 +207,12 @@ class JavascriptModulesPlugin {
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
chunkGraph,
codeGenerationResults
},
hooks
);
} else if (chunk.hasRuntime()) {
const hash = options.hash;
filenameTemplate =
chunk.filenameTemplate || outputOptions.filename;
@ -215,7 +224,8 @@ class JavascriptModulesPlugin {
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
chunkGraph,
codeGenerationResults
},
hooks
);
@ -239,7 +249,8 @@ class JavascriptModulesPlugin {
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
chunkGraph,
codeGenerationResults
},
hooks
);
@ -249,6 +260,7 @@ class JavascriptModulesPlugin {
render,
filenameTemplate,
pathOptions: {
hash,
chunk,
contentHashType: "javascript"
},
@ -278,8 +290,12 @@ class JavascriptModulesPlugin {
);
for (const key of Object.keys(bootstrap)) {
hash.update(key);
for (const line of bootstrap[key]) {
hash.update(line);
if (Array.isArray(bootstrap[key])) {
for (const line of bootstrap[key]) {
hash.update(line);
}
} else {
hash.update(JSON.stringify(bootstrap[key]));
}
}
}
@ -329,66 +345,70 @@ class JavascriptModulesPlugin {
* @param {Module} module the rendered module
* @param {RenderContext} renderContext options object
* @param {CompilationHooks} hooks hooks
* @param {boolean | "strict"} factory true: renders as factory method, "strict": renders as factory method already in strict scope, false: pure module content
* @returns {Source} the newly generated source from rendering
*/
renderModule(module, renderContext, hooks) {
renderModule(module, renderContext, hooks, factory) {
const {
chunkGraph,
moduleGraph,
runtimeTemplate,
dependencyTemplates
codeGenerationResults
} = renderContext;
try {
const moduleSource = module.source({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
type: "javascript"
});
const moduleSource = codeGenerationResults
.get(module)
.sources.get("javascript");
if (!moduleSource) return null;
const moduleSourcePostContent = tryRunOrWebpackError(
() =>
hooks.renderModuleContent.call(moduleSource, module, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderModuleContent"
);
const source = new ConcatSource();
const args = [];
const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
module
);
const needModule = runtimeRequirements.has(RuntimeGlobals.module);
const needExports = runtimeRequirements.has(RuntimeGlobals.exports);
const needRequire =
runtimeRequirements.has(RuntimeGlobals.require) ||
runtimeRequirements.has(RuntimeGlobals.requireScope);
const needThisAsExports = runtimeRequirements.has(
RuntimeGlobals.thisAsExports
);
if (needExports || needRequire || needModule)
args.push(
needModule
? module.moduleArgument
: "__unused_webpack_" + module.moduleArgument
let moduleSourcePostContainer;
if (factory) {
const source = new ConcatSource();
const args = [];
const runtimeRequirements = chunkGraph.getModuleRuntimeRequirements(
module
);
if (needExports || needRequire)
args.push(
needExports
? module.exportsArgument
: "__unused_webpack_" + module.exportsArgument
const needModule = runtimeRequirements.has(RuntimeGlobals.module);
const needExports = runtimeRequirements.has(RuntimeGlobals.exports);
const needRequire =
runtimeRequirements.has(RuntimeGlobals.require) ||
runtimeRequirements.has(RuntimeGlobals.requireScope);
const needThisAsExports = runtimeRequirements.has(
RuntimeGlobals.thisAsExports
);
if (needExports || needRequire || needModule)
args.push(
needModule
? module.moduleArgument
: "__unused_webpack_" + module.moduleArgument
);
if (needExports || needRequire)
args.push(
needExports
? module.exportsArgument
: "__unused_webpack_" + module.exportsArgument
);
if (needRequire) args.push("__webpack_require__");
if (!needThisAsExports && runtimeTemplate.supportsArrowFunction()) {
source.add("/***/ ((" + args.join(", ") + ") => {\n\n");
} else {
source.add("/***/ (function(" + args.join(", ") + ") {\n\n");
}
if (module.buildInfo.strict && factory !== "strict") {
source.add('"use strict";\n');
}
source.add(moduleSourcePostContent);
source.add("\n\n/***/ })");
moduleSourcePostContainer = tryRunOrWebpackError(
() => hooks.renderModuleContainer.call(source, module, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderModuleContainer"
);
if (needRequire) args.push("__webpack_require__");
if (!needThisAsExports && runtimeTemplate.supportsArrowFunction()) {
source.add("/***/ ((" + args.join(", ") + ") => {\n\n");
} else {
source.add("/***/ (function(" + args.join(", ") + ") {\n\n");
moduleSourcePostContainer = moduleSourcePostContent;
}
if (module.buildInfo.strict) source.add('"use strict";\n');
source.add(moduleSourcePostContent);
source.add("\n\n/***/ })");
const moduleSourcePostContainer = tryRunOrWebpackError(
() => hooks.renderModuleContainer.call(source, module, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderModuleContainer"
);
return tryRunOrWebpackError(
() =>
hooks.renderModulePackage.call(
@ -410,12 +430,14 @@ class JavascriptModulesPlugin {
* @returns {Source} the rendered source
*/
renderChunk(renderContext, hooks) {
const chunk = renderContext.chunk;
const moduleSources = Template.renderChunkModules(
renderContext,
m => m.getSourceTypes().has("javascript"),
module => this.renderModule(module, renderContext, hooks)
);
const { chunk, chunkGraph } = renderContext;
const modules = chunkGraph
.getOrderedChunkModules(chunk, compareModulesByIdOrIdentifier(chunkGraph))
.filter(m => m.getSourceTypes().has("javascript"));
const moduleSources =
Template.renderChunkModules(renderContext, modules, module =>
this.renderModule(module, renderContext, hooks, true)
) || new RawSource("{}");
let source = tryRunOrWebpackError(
() => hooks.renderChunk.call(moduleSources, renderContext),
"JavascriptModulesPlugin.getCompilationHooks().renderChunk"
@ -438,38 +460,78 @@ class JavascriptModulesPlugin {
renderMain(renderContext, hooks) {
const { chunk, chunkGraph, runtimeTemplate } = renderContext;
let source = new ConcatSource();
if (runtimeTemplate.supportsConst()) {
source.add("/******/ (() => { // webpackBootstrap\n");
} else {
source.add("/******/ (function() { // webpackBootstrap\n");
}
source.add("/******/ \tvar __webpack_modules__ = (");
source.add(
Template.renderChunkModules(
renderContext,
m => m.getSourceTypes().has("javascript"),
module => this.renderModule(module, renderContext, hooks),
"/******/ \t"
)
);
source.add(");\n");
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
const iife = runtimeTemplate.isIIFE();
const bootstrap = this.renderBootstrap(renderContext, hooks);
source.add(
"/************************************************************************/\n"
const allModules = chunkGraph
.getOrderedChunkModules(chunk, compareModulesByIdOrIdentifier(chunkGraph))
.filter(m => m.getSourceTypes().has("javascript"));
const allStrict = allModules.every(m => m.buildInfo.strict);
let inlinedModules;
if (bootstrap.allowInlineStartup) {
inlinedModules = new Set(chunkGraph.getChunkEntryModulesIterable(chunk));
}
let source = new ConcatSource();
let prefix;
if (iife) {
if (runtimeTemplate.supportsConst()) {
source.add("/******/ (() => { // webpackBootstrap\n");
} else {
source.add("/******/ (function() { // webpackBootstrap\n");
}
prefix = "/******/ \t";
} else {
prefix = "/******/ ";
}
if (allStrict) {
source.add(prefix + '"use strict";\n');
}
const chunkModules = Template.renderChunkModules(
renderContext,
inlinedModules
? allModules.filter(m => !inlinedModules.has(m))
: allModules,
module =>
this.renderModule(
module,
renderContext,
hooks,
allStrict ? "strict" : true
),
prefix
);
source.add(
new PrefixSource(
"/******/",
new OriginalSource(
Template.prefix(bootstrap.header, " \t") + "\n",
"webpack/bootstrap"
if (
chunkModules ||
runtimeRequirements.has(RuntimeGlobals.moduleFactories) ||
runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly)
) {
source.add(prefix + "var __webpack_modules__ = (");
source.add(chunkModules || "{}");
source.add(");\n");
source.add(
"/************************************************************************/\n"
);
}
if (bootstrap.header.length > 0) {
source.add(
new PrefixSource(
prefix,
new OriginalSource(
Template.asString(bootstrap.header) + "\n",
"webpack/bootstrap"
)
)
)
);
);
source.add(
"/************************************************************************/\n"
);
}
const runtimeModules = renderContext.chunkGraph.getChunkRuntimeModulesInOrder(
chunk
@ -477,25 +539,51 @@ class JavascriptModulesPlugin {
if (runtimeModules.length > 0) {
source.add(
"/************************************************************************/\n"
new PrefixSource(
prefix,
Template.renderRuntimeModules(runtimeModules, renderContext)
)
);
source.add(
Template.renderMainRuntimeModules(runtimeModules, renderContext)
"/************************************************************************/\n"
);
}
source.add(
"/************************************************************************/\n"
);
source.add(
new PrefixSource(
"/******/",
new OriginalSource(
Template.prefix(bootstrap.startup, " \t") + "\n",
"webpack/startup"
if (inlinedModules) {
for (const m of inlinedModules) {
const renderedModule = this.renderModule(
m,
renderContext,
hooks,
false
);
if (renderedModule) {
const innerStrict = !allStrict && m.buildInfo.strict;
const iife = innerStrict || inlinedModules.size > 1 || chunkModules;
if (iife) {
source.add("!function() {\n");
if (innerStrict) source.add('"use strict";\n');
source.add(renderedModule);
source.add("\n}();\n");
} else {
source.add(renderedModule);
source.add("\n");
}
}
}
} else {
source.add(
new PrefixSource(
prefix,
new OriginalSource(
Template.asString(bootstrap.startup) + "\n",
"webpack/startup"
)
)
)
);
source.add("/******/ })()\n");
);
}
if (iife) {
source.add("/******/ })()\n");
}
/** @type {Source} */
let finalSource = tryRunOrWebpackError(
@ -519,21 +607,24 @@ class JavascriptModulesPlugin {
);
}
chunk.rendered = true;
return new ConcatSource(finalSource, ";");
return iife ? new ConcatSource(finalSource, ";") : finalSource;
}
/**
* @param {RenderBootstrapContext} renderContext options object
* @param {CompilationHooks} hooks hooks
* @returns {{ header: string[], startup: string[] }} the generated source of the bootstrap code
* @returns {{ header: string[], startup: string[], allowInlineStartup: boolean }} the generated source of the bootstrap code
*/
renderBootstrap(renderContext, hooks) {
const { chunkGraph, chunk, runtimeTemplate } = renderContext;
const { chunkGraph, moduleGraph, chunk, runtimeTemplate } = renderContext;
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
const requireFunction = runtimeRequirements.has(RuntimeGlobals.require);
const moduleCache = runtimeRequirements.has(RuntimeGlobals.moduleCache);
const moduleFactories = runtimeRequirements.has(
RuntimeGlobals.moduleFactories
);
const moduleUsed = runtimeRequirements.has(RuntimeGlobals.module);
const exportsUsed = runtimeRequirements.has(RuntimeGlobals.exports);
const requireScopeUsed = runtimeRequirements.has(
@ -555,12 +646,36 @@ class JavascriptModulesPlugin {
const result = {
header: [],
startup: []
startup: [],
allowInlineStartup: true
};
let buf = result.header;
let startup = result.startup;
if (result.allowInlineStartup && moduleFactories) {
startup.push(
"// module factories are used so entry inlining is disabled"
);
result.allowInlineStartup = false;
}
if (result.allowInlineStartup && moduleCache) {
startup.push("// module cache are used so entry inlining is disabled");
result.allowInlineStartup = false;
}
if (result.allowInlineStartup && interceptModuleExecution) {
startup.push(
"// module execution is intercepted so entry inlining is disabled"
);
result.allowInlineStartup = false;
}
if (result.allowInlineStartup && returnExportsFromRuntime) {
startup.push(
"// module exports must be returned from runtime so entry inlining is disabled"
);
result.allowInlineStartup = false;
}
if (useRequire || moduleCache) {
buf.push("// The module cache");
buf.push("var __webpack_module_cache__ = {};");
@ -577,27 +692,30 @@ class JavascriptModulesPlugin {
} else if (runtimeRequirements.has(RuntimeGlobals.requireScope)) {
buf.push("// The require scope");
buf.push("var __webpack_require__ = {};");
buf.push("");
}
if (runtimeRequirements.has(RuntimeGlobals.moduleFactories)) {
buf.push("");
if (
moduleFactories ||
runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly)
) {
buf.push("// expose the modules object (__webpack_modules__)");
buf.push(`${RuntimeGlobals.moduleFactories} = __webpack_modules__;`);
buf.push("");
}
if (moduleCache) {
buf.push("");
buf.push("// expose the module cache");
buf.push(`${RuntimeGlobals.moduleCache} = __webpack_module_cache__;`);
buf.push("");
}
if (interceptModuleExecution) {
buf.push("");
buf.push("// expose the module execution interceptor");
buf.push(`${RuntimeGlobals.interceptModuleExecution} = [];`);
buf.push("");
}
buf.push("");
if (!runtimeRequirements.has(RuntimeGlobals.startupNoDefault)) {
if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
/** @type {string[]} */
@ -614,15 +732,42 @@ class JavascriptModulesPlugin {
for (const entryModule of chunkGraph.getChunkEntryModulesIterable(
chunk
)) {
if (
result.allowInlineStartup &&
moduleGraph
.getIncomingConnections(entryModule)
.some(c => c.originModule)
) {
buf2.push(
"// This entry module is referenced by other modules so it can't be inlined"
);
result.allowInlineStartup = false;
}
const mayReturn =
--i === 0 && returnExportsFromRuntime ? "return " : "";
const moduleId = chunkGraph.getModuleId(entryModule);
const entryRuntimeRequirements = chunkGraph.getModuleRuntimeRequirements(
entryModule
);
let moduleIdExpr = JSON.stringify(moduleId);
if (runtimeRequirements.has(RuntimeGlobals.entryModuleId)) {
moduleIdExpr = `${RuntimeGlobals.entryModuleId} = ${moduleIdExpr}`;
}
if (useRequire) {
buf2.push(`${mayReturn}__webpack_require__(${moduleIdExpr});`);
if (result.allowInlineStartup) {
if (entryRuntimeRequirements.has(RuntimeGlobals.module)) {
result.allowInlineStartup = false;
buf2.push(
"// This entry module used 'module' so it can't be inlined"
);
} else if (entryRuntimeRequirements.has(RuntimeGlobals.exports)) {
buf2.push(
"// This entry module used 'exports' so it can't be inlined"
);
result.allowInlineStartup = false;
}
}
} else if (requireScopeUsed) {
buf2.push(
`__webpack_modules__[${moduleIdExpr}](0, 0, __webpack_require__);`
@ -632,6 +777,7 @@ class JavascriptModulesPlugin {
}
}
if (runtimeRequirements.has(RuntimeGlobals.startup)) {
result.allowInlineStartup = false;
buf.push(
Template.asString([
"// the startup function",
@ -641,6 +787,7 @@ class JavascriptModulesPlugin {
)};`
])
);
buf.push("");
startup.push("// run startup");
startup.push(`return ${RuntimeGlobals.startup}();`);
} else {
@ -659,8 +806,10 @@ class JavascriptModulesPlugin {
)}`
])
);
buf.push("");
}
} else if (runtimeRequirements.has(RuntimeGlobals.startup)) {
result.allowInlineStartup = false;
startup.push("// run startup");
startup.push(`return ${RuntimeGlobals.startup}();`);
}

View File

@ -83,9 +83,16 @@ class LibraryTemplatePlugin {
apply(compiler) {
if (this.options.libraryExport) {
const ExportPropertyTemplatePlugin = require("./ExportPropertyTemplatePlugin");
new ExportPropertyTemplatePlugin(this.options.libraryExport).apply(
compiler
);
new ExportPropertyTemplatePlugin(
this.options.libraryExport,
"used a library export"
).apply(compiler);
} else {
const FlagEntryExportAsUsedPlugin = require("./FlagEntryExportAsUsedPlugin");
new FlagEntryExportAsUsedPlugin(
this.options.libraryTarget !== "module",
"used a library export"
).apply(compiler);
}
switch (this.options.libraryTarget) {
case "umd":
@ -190,6 +197,9 @@ class LibraryTemplatePlugin {
}).apply(compiler);
break;
}
case "module":
// TODO
break;
default:
throw new Error(
`${this.options.libraryTarget} is not a valid Library target`

View File

@ -34,6 +34,20 @@ const makeSerializable = require("./util/makeSerializable");
* @property {string=} type the type of source that should be generated
*/
/**
* @typedef {Object} CodeGenerationContext
* @property {DependencyTemplates} dependencyTemplates the dependency templates
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
*/
/**
* @typedef {Object} CodeGenerationResult
* @property {Map<string, Source>} sources the resulting sources for all source types
* @property {Iterable<string>} runtimeRequirements the runtime requirements
*/
/**
* @typedef {Object} LibIdentOptions
* @property {string} context absolute context path to which lib ident is relative to
@ -522,11 +536,22 @@ class Module extends DependenciesBlock {
/**
* @abstract
* @deprecated Use codeGeneration() instead
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
*/
source(sourceContext) {
throw new Error("Module.source: Must be overriden");
if (this.codeGeneration === Module.prototype.codeGeneration) {
throw new Error("Module.source: Must be overriden");
}
const sources = this.codeGeneration(sourceContext).sources;
return sourceContext.type
? sources.get(sourceContext.type)
: sources.get(
this.getSourceTypes()
.values()
.next().value
);
}
/**
@ -554,12 +579,41 @@ class Module extends DependenciesBlock {
}
/**
* @abstract
* @deprecated Use codeGeneration() instead
* Get a list of runtime requirements
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements(context) {
return null;
if (this.codeGeneration === Module.prototype.codeGeneration) {
return null;
}
return this.codeGeneration(context).runtimeRequirements;
}
/**
* @param {CodeGenerationContext} context context for code generation
* @returns {CodeGenerationResult} result
*/
codeGeneration(context) {
// Best override this method
const sources = new Map();
for (const type of this.getSourceTypes()) {
if (type !== "unknown") {
sources.set(
type,
this.source({
...context,
type
})
);
}
}
return {
sources,
runtimeRequirements: this.getRuntimeRequirements(context)
};
}
/**

View File

@ -218,6 +218,21 @@ class ExportsInfo {
return changed;
}
setAllKnownExportsUsed() {
let changed = false;
if (this._isUsed === false) {
this._isUsed = true;
changed = true;
}
for (const exportInfo of this._exports.values()) {
if (exportInfo.used !== UsageState.Used) {
exportInfo.used = UsageState.Used;
changed = true;
}
}
return changed;
}
setUsedAsNamedExportType() {
let changed = false;
if (this._isUsed === false) {

View File

@ -35,9 +35,10 @@ const makeSerializable = require("./util/makeSerializable");
/** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */
/** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
/** @typedef {import("./Module").SourceContext} SourceContext */
/** @typedef {import("./RequestShortener")} RequestShortener */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("./util/Hash")} Hash */
@ -90,8 +91,9 @@ makeSerializable(
);
/**
* @typedef {Object} CachedSourceEntry
* @typedef {Object} CachedCodeGenerationEntry
* @property {string} hash the hash value
* @property {CodeGenerationResult} result result of code generation
*/
/**
@ -162,8 +164,8 @@ class NormalModule extends Module {
this._source = null;
/** @private @type {Map<string, number>} **/
this._sourceSizes = new Map();
/** @private @type {Map<string, GenerateSourceResult & CachedSourceEntry>} */
this._cachedSources = new Map();
/** @private @type {CachedCodeGenerationEntry} */
this._cachedCodeGeneration = undefined;
// Cache
this._lastSuccessfulBuildMeta = {};
@ -575,7 +577,7 @@ class NormalModule extends Module {
};
return this.doBuild(options, compilation, resolver, fs, err => {
this._cachedSources.clear();
this._cachedCodeGeneration = undefined;
// if we have an error mark module as failed and exit
if (err) {
@ -659,14 +661,6 @@ class NormalModule extends Module {
return `${hash}-${dtHash}`;
}
/**
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
*/
source(sourceContext) {
return this._generateSource(sourceContext).source;
}
/**
* @returns {Set<string>} types availiable (do not mutate)
*/
@ -675,31 +669,20 @@ class NormalModule extends Module {
}
/**
* @typedef {Object} GenerateSourceContext
* @param {CodeGenerationContext} context context for code generation
* @returns {CodeGenerationResult} result
*/
/**
* @typedef {Object} GenerateSourceResult
* @property {Source} source the generated source
* @property {Set<string>} runtimeRequirements the requirements for the runtime
*/
/**
* @param {SourceContext} sourceContext source context
* @returns {GenerateSourceResult} generated source result
*/
_generateSource({
codeGeneration({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
type = "javascript"
chunkGraph
}) {
const hashDigest = this._getHashDigest(chunkGraph, dependencyTemplates);
const cacheEntry = this._cachedSources.get(type);
const cacheEntry = this._cachedCodeGeneration;
if (cacheEntry !== undefined && cacheEntry.hash === hashDigest) {
// We can reuse the cached data
return cacheEntry;
return cacheEntry.result;
}
/** @type {Set<string>} */
@ -711,32 +694,33 @@ class NormalModule extends Module {
runtimeRequirements.add(RuntimeGlobals.thisAsExports);
}
const source = this.error
? new RawSource(
"throw new Error(" + JSON.stringify(this.error.message) + ");"
)
: this.generator.generate(this, {
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
runtimeRequirements,
type
});
const sources = new Map();
for (const type of this.generator.getTypes()) {
const source = this.error
? new RawSource(
"throw new Error(" + JSON.stringify(this.error.message) + ");"
)
: this.generator.generate(this, {
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
runtimeRequirements,
type
});
const cachedSource = new CachedSource(source);
sources.set(type, new CachedSource(source));
}
// TODO remove cast when webpack-sources types are fixed
// CachedSource is not a Source?
const fixedSource = /** @type {TODO} */ (cachedSource);
/** @type {GenerateSourceResult & CachedSourceEntry} */
/** @type {CodeGenerationResult} */
const resultEntry = {
source: fixedSource,
runtimeRequirements,
sources,
runtimeRequirements
};
this._cachedCodeGeneration = {
result: resultEntry,
hash: hashDigest
};
this._cachedSources.set(type, resultEntry);
return resultEntry;
}
@ -775,15 +759,6 @@ class NormalModule extends Module {
});
}
/**
* Get a list of runtime requirements
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements(context) {
return this._generateSource(context).runtimeRequirements;
}
/**
* @param {string=} type the source type for which the size should be estimated
* @returns {number} the estimated size of the module (must be non-zero)
@ -817,7 +792,7 @@ class NormalModule extends Module {
write(this._source);
write(this._sourceSizes);
write(this.error);
write(this._cachedSources);
write(this._cachedCodeGeneration);
write(this._lastSuccessfulBuildMeta);
write(this._forceBuild);
super.serialize(context);
@ -847,7 +822,7 @@ class NormalModule extends Module {
this._source = read();
this._sourceSizes = read();
this.error = read();
this._cachedSources = read();
this._cachedCodeGeneration = read();
this._lastSuccessfulBuildMeta = read();
this._forceBuild = read();
super.deserialize(context);

View File

@ -273,6 +273,7 @@ class ProgressPlugin {
recordModules: "record modules",
recordChunks: "record chunks",
beforeModuleHash: "module hashing",
beforeCodeGeneration: "code generation",
beforeRuntimeRequirements: "runtime requirements",
beforeHash: "hashing",
afterHash: "after hashing",

View File

@ -13,8 +13,9 @@ const makeSerializable = require("./util/makeSerializable");
/** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
/** @typedef {import("./Module").SourceContext} SourceContext */
/** @typedef {import("./RequestShortener")} RequestShortener */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("./WebpackError")} WebpackError */
@ -89,15 +90,20 @@ class RawModule extends Module {
}
/**
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
* @param {CodeGenerationContext} context context for code generation
* @returns {CodeGenerationResult} result
*/
source(sourceContext) {
codeGeneration(context) {
const sources = new Map();
if (this.useSourceMap) {
return new OriginalSource(this.sourceStr, this.identifier());
sources.set(
"javascript",
new OriginalSource(this.sourceStr, this.identifier())
);
} else {
return new RawSource(this.sourceStr);
sources.set("javascript", new RawSource(this.sourceStr));
}
return { sources, runtimeRequirements: null };
}
/**

View File

@ -25,6 +25,11 @@ exports.exports = "__webpack_exports__";
*/
exports.thisAsExports = "top-level-this-exports";
/**
* top-level this need to be the exports object
*/
exports.supportsSymbolsDeconflicting = "supports-symbols-deconflicting";
/**
* top-level this need to be the exports object
*/
@ -55,6 +60,11 @@ exports.moduleCache = "__webpack_require__.c";
*/
exports.moduleFactories = "__webpack_require__.m";
/**
* the module functions, with only write access
*/
exports.moduleFactoriesAddOnly = "__webpack_require__.m (add only)";
/**
* the chunk ensure function
*/

View File

@ -12,14 +12,15 @@ const Module = require("./Module");
/** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */
/** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
/** @typedef {import("./Module").SourceContext} SourceContext */
/** @typedef {import("./RequestShortener")} RequestShortener */
/** @typedef {import("./WebpackError")} WebpackError */
/** @typedef {import("./util/Hash")} Hash */
/** @typedef {SourceContext} GenerateContext */
/** @typedef {CodeGenerationContext} GenerateContext */
const TYPES = new Set(["runtime"]);
@ -114,13 +115,22 @@ class RuntimeModule extends Module {
}
/**
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
* @param {CodeGenerationContext} context context for code generation
* @returns {CodeGenerationResult} result
*/
source(sourceContext) {
codeGeneration(context) {
const sources = new Map();
const generatedCode = this.getGeneratedCode();
if (!generatedCode) return null;
return new OriginalSource(generatedCode, this.identifier());
if (generatedCode) {
sources.set(
"runtime",
new OriginalSource(generatedCode, this.identifier())
);
}
return {
sources,
runtimeRequirements: null
};
}
/**

View File

@ -34,6 +34,7 @@ const GLOBALS_ON_REQUIRE = [
RuntimeGlobals.makeNamespaceObject,
RuntimeGlobals.moduleCache,
RuntimeGlobals.moduleFactories,
RuntimeGlobals.moduleFactoriesAddOnly,
RuntimeGlobals.interceptModuleExecution,
RuntimeGlobals.publicPath,
RuntimeGlobals.scriptNonce,

View File

@ -35,6 +35,10 @@ class RuntimeTemplate {
this.requestShortener = requestShortener;
}
isIIFE() {
return this.outputOptions.iife;
}
supportsConst() {
return this.outputOptions.ecmaVersion >= 2015;
}

View File

@ -7,10 +7,7 @@
const { ConcatSource, PrefixSource } = require("webpack-sources");
const HotUpdateChunk = require("./HotUpdateChunk");
const {
compareIds,
compareModulesByIdOrIdentifier
} = require("./util/comparators");
const { compareIds } = require("./util/comparators");
/** @typedef {import("webpack-sources").ConcatSource} ConcatSource */
/** @typedef {import("webpack-sources").Source} Source */
@ -20,6 +17,7 @@ const {
/** @typedef {import("./Compilation").PathData} PathData */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("./ModuleGraph")} ModuleGraph */
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
/** @typedef {import("./ModuleTemplate").RenderContext} RenderContext */
@ -44,6 +42,7 @@ const MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g;
* @property {string} hash
* @property {string} fullHash
* @property {TODO} outputOptions
* @property {Map<Module, CodeGenerationResult>} codeGenerationResults
* @property {{javascript: ModuleTemplate}} moduleTemplates
* @property {DependencyTemplates} dependencyTemplates
* @property {RuntimeTemplate} runtimeTemplate
@ -225,22 +224,14 @@ class Template {
/**
* @param {RenderContext} renderContext render context
* @param {ModuleFilterPredicate} filterFn function used to filter modules from chunk to render
* @param {Module[]} modules modules to render
* @param {function(Module): Source} renderModule function to render a module
* @param {string=} prefix applying prefix strings
* @returns {Source} rendered chunk modules in a Source object
*/
static renderChunkModules(
renderContext,
filterFn,
renderModule,
prefix = ""
) {
static renderChunkModules(renderContext, modules, renderModule, prefix = "") {
const { chunk, chunkGraph } = renderContext;
var source = new ConcatSource();
const modules = chunkGraph
.getOrderedChunkModules(chunk, compareModulesByIdOrIdentifier(chunkGraph))
.filter(filterFn);
let removedModules;
if (chunk instanceof HotUpdateChunk) {
removedModules = chunk.removedModules;
@ -249,14 +240,13 @@ class Template {
modules.length === 0 &&
(!removedModules || removedModules.length === 0)
) {
source.add("[]");
return source;
return null;
}
/** @type {{id: string|number, source: Source|string}[]} */
const allModules = modules.map(module => {
return {
id: chunkGraph.getModuleId(module),
source: renderModule(module)
source: renderModule(module) || "false"
};
});
if (removedModules && removedModules.length > 0) {
@ -321,36 +311,26 @@ class Template {
static renderRuntimeModules(runtimeModules, renderContext) {
const source = new ConcatSource();
for (const module of runtimeModules) {
const moduleSource = module.source({
const codeGenResult = module.codeGeneration({
chunkGraph: renderContext.chunkGraph,
dependencyTemplates: renderContext.dependencyTemplates,
moduleGraph: renderContext.moduleGraph,
runtimeTemplate: renderContext.runtimeTemplate,
type: "runtime"
runtimeTemplate: renderContext.runtimeTemplate
});
if (moduleSource) {
source.add(Template.toNormalComment(module.identifier()) + "\n");
source.add("!function() {\n");
source.add('\t"use strict";\n');
source.add(new PrefixSource("\t", moduleSource));
source.add("\n}();\n\n");
if (codeGenResult) {
const moduleSource = codeGenResult.sources.get("runtime");
if (moduleSource) {
source.add(Template.toNormalComment(module.identifier()) + "\n");
source.add("!function() {\n");
source.add('\t"use strict";\n');
source.add(new PrefixSource("\t", moduleSource));
source.add("\n}();\n\n");
}
}
}
return source;
}
/**
* @param {RuntimeModule[]} runtimeModules array of runtime modules in order
* @param {RenderContext} renderContext render context
* @returns {Source} rendered main runtime modules in a Source object
*/
static renderMainRuntimeModules(runtimeModules, renderContext) {
return new PrefixSource(
"/******/ \t",
this.renderRuntimeModules(runtimeModules, renderContext)
);
}
/**
* @param {RuntimeModule[]} runtimeModules array of runtime modules in order
* @param {RenderContext} renderContext render context

View File

@ -300,6 +300,19 @@ class WebpackOptionsApply extends OptionsApply {
new JavascriptModulesPlugin().apply(compiler);
new JsonModulesPlugin().apply(compiler);
if (!options.experiments.outputModule) {
if (options.output.module) {
throw new Error(
"'output.module: true' is only allowed when 'experiements.outputModule' is enabled"
);
}
if (options.output.libraryTarget === "module") {
throw new Error(
"'output.libraryTarget: \"module\"' is only allowed when 'experiements.outputModule' is enabled"
);
}
}
if (options.experiments.asset) {
const AssetModulesPlugin = require("./asset/AssetModulesPlugin");
new AssetModulesPlugin().apply(compiler);

View File

@ -42,6 +42,7 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
this.set("experiments.topLevelAwait", false);
this.set("experiments.syncWebAssembly", false);
this.set("experiments.asyncWebAssembly", false);
this.set("experiments.outputModule", false);
this.set("entry", "./src");
@ -199,6 +200,12 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
});
this.set("output.filename", "[name].js");
this.set(
"output.module",
"make",
options => options.experiments.outputModule
);
this.set("output.iife", "make", options => !options.output.module);
this.set("output.ecmaVersion", 2015);
this.set("output.chunkFilename", "make", options => {
const filename = options.output.filename;
@ -252,7 +259,9 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
this.set("output.devtoolNamespace", "make", options => {
return getDevtoolNamespace(options.output.library);
});
this.set("output.libraryTarget", "var");
this.set("output.libraryTarget", "make", options => {
return options.output.module ? "module" : "var";
});
this.set("output.path", path.join(process.cwd(), "dist"));
this.set(
"output.pathinfo",
@ -263,7 +272,9 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
this.set("output.hotUpdateChunkFilename", "[id].[fullhash].hot-update.js");
this.set("output.hotUpdateMainFilename", "[fullhash].hot-update.json");
this.set("output.crossOriginLoading", false);
this.set("output.jsonpScriptType", false);
this.set("output.jsonpScriptType", "make", options => {
return options.output.module ? "module" : false;
});
this.set("output.chunkLoadTimeout", 120000);
this.set("output.hashFunction", "md4");
this.set("output.hashDigest", "hex");
@ -434,6 +445,7 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
(options.plugins &&
options.plugins.some(p => p instanceof SourceMapDevToolPlugin)),
terserOptions: {
module: options.output.module,
ecma:
options.output.ecmaVersion > 2000
? options.output.ecmaVersion - 2009

View File

@ -40,8 +40,8 @@ class AssetModulesPlugin {
});
compilation.hooks.renderManifest.tap(plugin, (result, options) => {
const { chunkGraph, moduleGraph } = compilation;
const { chunk, dependencyTemplates, runtimeTemplate } = options;
const { chunkGraph } = compilation;
const { chunk, runtimeTemplate, codeGenerationResults } = options;
const { outputOptions } = runtimeTemplate;
@ -55,13 +55,7 @@ class AssetModulesPlugin {
result.push({
render: () =>
module.source({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
type
}),
codeGenerationResults.get(module).sources.get(type),
filenameTemplate,
pathOptions: {
module,

View File

@ -58,7 +58,7 @@ class NodeTemplatePlugin {
const handler = (chunk, set) => {
if (onceForChunkSet.has(chunk)) return;
onceForChunkSet.add(chunk);
set.add(RuntimeGlobals.moduleFactories);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
compilation.addRuntimeModule(chunk, new ChunkLoadingRuntimeModule(set));
};
@ -83,7 +83,7 @@ class NodeTemplatePlugin {
set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
set.add(RuntimeGlobals.moduleCache);
set.add(RuntimeGlobals.hmrModuleData);
set.add(RuntimeGlobals.moduleFactories);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
});
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.hmrDownloadManifest)

View File

@ -6,7 +6,11 @@
"use strict";
const eslintScope = require("eslint-scope");
const { ConcatSource, ReplaceSource } = require("webpack-sources");
const {
CachedSource,
ConcatSource,
ReplaceSource
} = require("webpack-sources");
const DependencyTemplate = require("../DependencyTemplate");
const JavascriptParser = require("../JavascriptParser");
const Module = require("../Module");
@ -33,14 +37,20 @@ const propertyAccess = require("../util/propertyAccess");
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
/** @typedef {import("../Module").CodeGenerationContext} CodeGenerationContext */
/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */
/** @typedef {import("../Module").SourceContext} SourceContext */
/** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../RequestShortener")} RequestShortener */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("../WebpackError")} WebpackError */
/** @typedef {import("../util/Hash")} Hash */
/**
* @typedef {Object} CachedSourceEntry
* @property {string} hash the hash value
*/
/**
* @typedef {Object} ReexportInfo
* @property {Module} module
@ -58,6 +68,7 @@ const propertyAccess = require("../util/propertyAccess");
* @property {Object} ast
* @property {Source} internalSource
* @property {ReplaceSource} source
* @property {Iterable<string>} runtimeRequirements
* @property {TODO} globalScope
* @property {TODO} moduleScope
* @property {TODO} internalNames
@ -766,10 +777,20 @@ class ConcatenatedModule extends Module {
}
/**
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
* @param {CodeGenerationContext} context context for code generation
* @returns {CodeGenerationResult} result
*/
source({ dependencyTemplates, runtimeTemplate, moduleGraph, chunkGraph }) {
codeGeneration({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
}) {
/** @type {Set<string>} */
const runtimeRequirements = new Set([
RuntimeGlobals.supportsSymbolsDeconflicting
]);
const requestShortener = runtimeTemplate.requestShortener;
// Metainfo for each module
const modulesWithInfo = this._getModulesWithInfo(moduleGraph);
@ -985,7 +1006,7 @@ class ConcatenatedModule extends Module {
result.add(
runtimeTemplate.defineEsModuleFlagStatement({
exportsArgument: this.exportsArgument,
runtimeRequirements: new Set()
runtimeRequirements
})
);
}
@ -994,26 +1015,35 @@ class ConcatenatedModule extends Module {
for (const info of modulesWithInfo) {
if (info.type === "concatenated" && info.namespaceObjectSource) {
result.add(info.namespaceObjectSource);
runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
}
}
// evaluate modules in order
for (const info of modulesWithInfo) {
switch (info.type) {
case "concatenated":
case "concatenated": {
result.add(
`\n// CONCATENATED MODULE: ${info.module.readableIdentifier(
requestShortener
)}\n`
);
result.add(info.source);
if (info.runtimeRequirements) {
for (const r of info.runtimeRequirements) {
runtimeRequirements.add(r);
}
}
break;
}
case "external":
result.add(
`\n// EXTERNAL MODULE: ${info.module.readableIdentifier(
requestShortener
)}\n`
);
runtimeRequirements.add(RuntimeGlobals.require);
result.add(
`var ${info.name} = __webpack_require__(${JSON.stringify(
chunkGraph.getModuleId(info.module)
@ -1021,16 +1051,19 @@ class ConcatenatedModule extends Module {
);
if (info.interopNamespaceObjectUsed) {
if (info.module.buildMeta.exportsType === "named") {
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
result.add(
`var ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${info.name}, 2);\n`
);
} else if (!info.module.buildMeta.exportsType) {
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
result.add(
`var ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${info.name});\n`
);
}
}
if (info.interopDefaultAccessUsed) {
runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
result.add(
`var ${info.interopDefaultAccessName} = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${info.name});\n`
);
@ -1042,7 +1075,10 @@ class ConcatenatedModule extends Module {
}
}
return result;
return {
sources: new Map([["javascript", new CachedSource(result)]]),
runtimeRequirements
};
}
_analyseModule(
@ -1054,12 +1090,13 @@ class ConcatenatedModule extends Module {
) {
if (info.type === "concatenated") {
const m = info.module;
const source = m.source({
const codeGenResult = m.codeGeneration({
dependencyTemplates: innerDependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
});
const source = codeGenResult.sources.get("javascript");
const code = source.source();
let ast;
try {
@ -1092,6 +1129,7 @@ class ConcatenatedModule extends Module {
const globalScope = scopeManager.acquire(ast);
const moduleScope = globalScope.childScopes[0];
const resultSource = new ReplaceSource(source);
info.runtimeRequirements = codeGenResult.runtimeRequirements;
info.ast = ast;
info.internalSource = source;
info.source = resultSource;
@ -1100,6 +1138,17 @@ class ConcatenatedModule extends Module {
}
}
/**
* @param {ChunkGraph} chunkGraph the chunk graph
* @param {DependencyTemplates} dependencyTemplates dependency templates
* @returns {string} hash
*/
_getHashDigest(chunkGraph, dependencyTemplates) {
const hash = chunkGraph.getModuleHash(this);
const dtHash = dependencyTemplates.getHash();
return `${hash}-${dtHash}`;
}
/**
* @param {ModuleGraph} moduleGraph the module graph
* @returns {ModuleInfo[]} module info items
@ -1164,6 +1213,7 @@ class ConcatenatedModule extends Module {
index: idx,
ast: undefined,
internalSource: undefined,
runtimeRequirements: undefined,
source: undefined,
globalScope: undefined,
moduleScope: undefined,
@ -1287,60 +1337,6 @@ class ConcatenatedModule extends Module {
return nameWithNumber;
}
/**
* Get a list of runtime requirements
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements(context) {
const { dependencyTemplates, moduleGraph } = context;
// Metainfo for each module
const modulesWithInfo = this._getModulesWithInfo(moduleGraph);
// Create mapping from module to info
const moduleToInfoMap = modulesWithInfoToMap(modulesWithInfo);
// Configure template decorators for dependencies
const innerDependencyTemplates = this._getInnerDependencyTemplates(
dependencyTemplates,
moduleToInfoMap
);
const innerContext = {
...context,
dependencyTemplates: innerDependencyTemplates
};
const set = new Set([
RuntimeGlobals.exports, // TODO check if really used
RuntimeGlobals.makeNamespaceObject,
RuntimeGlobals.definePropertyGetters
]);
for (const info of this._orderedConcatenationList) {
switch (info.type) {
case "concatenated": {
const req = info.module.getRuntimeRequirements(innerContext);
if (req) {
for (const r of req) set.add(r);
}
break;
}
case "external": {
if (
!info.module.buildMeta.exportsType ||
info.module.buildMeta.exportsType === "named"
) {
set.add(RuntimeGlobals.createFakeNamespaceObject);
}
set.add(RuntimeGlobals.compatGetDefaultExport);
break;
}
}
}
return set;
}
/**
* @param {Hash} hash the hash used to track dependencies
* @param {ChunkGraph} chunkGraph the chunk graph

View File

@ -16,11 +16,12 @@ const AsyncWebAssemblyJavascriptGenerator = require("./AsyncWebAssemblyJavascrip
const AsyncWebAssemblyParser = require("./AsyncWebAssemblyParser");
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Template").RenderManifestOptions} RenderManifestOptions} */
/** @typedef {import("../Template").RenderManifestEntry} RenderManifestEntry} */
/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
/** @typedef {import("../Template").RenderManifestEntry} RenderManifestEntry */
/** @typedef {import("../Template").RenderManifestOptions} RenderManifestOptions */
/**
* @typedef {Object} RenderContext
@ -29,6 +30,7 @@ const AsyncWebAssemblyParser = require("./AsyncWebAssemblyParser");
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {Map<Module, CodeGenerationResult>} codeGenerationResults results of code generation
*/
/**
@ -104,9 +106,12 @@ class AsyncWebAssemblyModulesPlugin {
"WebAssemblyModulesPlugin",
(result, options) => {
const { moduleGraph, chunkGraph, runtimeTemplate } = compilation;
const chunk = options.chunk;
const outputOptions = options.outputOptions;
const dependencyTemplates = options.dependencyTemplates;
const {
chunk,
outputOptions,
dependencyTemplates,
codeGenerationResults
} = options;
for (const module of chunkGraph.getOrderedChunkModulesIterable(
chunk,
@ -125,7 +130,8 @@ class AsyncWebAssemblyModulesPlugin {
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
chunkGraph,
codeGenerationResults
},
hooks
),
@ -151,20 +157,11 @@ class AsyncWebAssemblyModulesPlugin {
}
renderModule(module, renderContext, hooks) {
const {
chunkGraph,
moduleGraph,
runtimeTemplate,
dependencyTemplates
} = renderContext;
const { codeGenerationResults } = renderContext;
try {
const moduleSource = module.source({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
type: "webassembly"
});
const moduleSource = codeGenerationResults
.get(module)
.sources.get("webassembly");
return tryRunOrWebpackError(
() =>
hooks.renderModuleContent.call(moduleSource, module, renderContext),

View File

@ -61,10 +61,8 @@ class WebAssemblyModulesPlugin {
compilation.hooks.renderManifest.tap(
"WebAssemblyModulesPlugin",
(result, options) => {
const { moduleGraph, chunkGraph, runtimeTemplate } = compilation;
const chunk = options.chunk;
const outputOptions = options.outputOptions;
const dependencyTemplates = options.dependencyTemplates;
const { chunkGraph } = compilation;
const { chunk, outputOptions, codeGenerationResults } = options;
for (const module of chunkGraph.getOrderedChunkModulesIterable(
chunk,
@ -76,12 +74,9 @@ class WebAssemblyModulesPlugin {
result.push({
render: () =>
module.source({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
}),
codeGenerationResults
.get(module)
.sources.get("webassembly"),
filenameTemplate,
pathOptions: {
module,

View File

@ -258,7 +258,7 @@ class JsonpTemplatePlugin {
const handler = (chunk, set) => {
if (onceForChunkSet.has(chunk)) return;
onceForChunkSet.add(chunk);
set.add(RuntimeGlobals.moduleFactories);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
compilation.addRuntimeModule(
chunk,
new JsonpChunkLoadingRuntimeModule(
@ -292,7 +292,7 @@ class JsonpTemplatePlugin {
set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
set.add(RuntimeGlobals.moduleCache);
set.add(RuntimeGlobals.hmrModuleData);
set.add(RuntimeGlobals.moduleFactories);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
});
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.hmrDownloadManifest)

View File

@ -80,7 +80,7 @@ class WebWorkerTemplatePlugin {
const handler = (chunk, set) => {
if (onceForChunkSet.has(chunk)) return;
onceForChunkSet.add(chunk);
set.add(RuntimeGlobals.moduleFactories);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
compilation.addRuntimeModule(
chunk,
new ImportScriptsChunkLoadingRuntimeModule(set)
@ -109,7 +109,7 @@ class WebWorkerTemplatePlugin {
set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
set.add(RuntimeGlobals.moduleCache);
set.add(RuntimeGlobals.hmrModuleData);
set.add(RuntimeGlobals.moduleFactories);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
});
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.hmrDownloadManifest)

View File

@ -118,6 +118,10 @@
"description": "Support .mjs files as way to define strict ESM file (node.js)",
"type": "boolean"
},
"outputModule": {
"description": "Allow outputing javascript files as module source type",
"type": "boolean"
},
"syncWebAssembly": {
"description": "Support WebAssembly as synchronous EcmaScript Module (outdated)",
"type": "boolean"
@ -1223,6 +1227,10 @@
"type": "string",
"absolutePath": false
},
"iife": {
"description": "Wrap javascript code into IIFEs to avoid leaking into global scope.",
"type": "boolean"
},
"jsonpFunction": {
"description": "The JSONP function used by webpack for async loading of chunks.",
"type": "string"
@ -1264,6 +1272,7 @@
"description": "Type of library",
"enum": [
"var",
"module",
"assign",
"this",
"window",
@ -1280,6 +1289,10 @@
"system"
]
},
"module": {
"description": "Output javascript files as module source type.",
"type": "boolean"
},
"path": {
"description": "The output directory as **absolute path** (required).",
"type": "string",

View File

@ -1,8 +1,6 @@
"use strict";
const RawModule = require("../lib/RawModule");
const OriginalSource = require("webpack-sources").OriginalSource;
const RawSource = require("webpack-sources").RawSource;
const RequestShortener = require("../lib/RequestShortener");
const path = require("path");
@ -35,29 +33,4 @@ describe("RawModule", () => {
}
);
});
describe("source", () => {
it(
"returns a new OriginalSource instance with sourceStr attribute and " +
"return value of identifier() function provided as constructor arguments",
() => {
const originalSource = new OriginalSource(
myRawModule.sourceStr,
myRawModule.identifier()
);
myRawModule.useSourceMap = true;
expect(myRawModule.source()).toEqual(originalSource);
}
);
it(
"returns a new RawSource instance with sourceStr attribute provided " +
"as constructor argument if useSourceMap is falsy",
() => {
const rawSource = new RawSource(myRawModule.sourceStr);
myRawModule.useSourceMap = false;
expect(myRawModule.source()).toEqual(rawSource);
}
);
});
});

View File

@ -220,10 +220,10 @@ describe("Stats", () => {
],
"emitted": true,
"info": Object {
"size": 2081,
"size": 2242,
},
"name": "entryB.js",
"size": 2081,
"size": 2242,
},
],
"assetsByChunkName": Object {

File diff suppressed because it is too large Load Diff

View File

@ -18,14 +18,9 @@ it("should include only one use strict per module", function() {
matches.sort();
expect(matches).toEqual([
'/* unused harmony default export */ var _unused_webpack_default_export = ("a");',
"/******/ // Check if module is in cache",
"/******/ // define __esModule on exports",
"/******/ // define getter functions for harmony exports",
"__webpack_require__.r(__webpack_exports__);",
"__webpack_require__.r(__webpack_exports__);",
"__webpack_require__.r(__webpack_exports__);",
"__webpack_require__.r(__webpack_exports__);",
'it("should include only one use strict per module", function() {'
"/******/ var __webpack_modules__ = ({"
]);
});

View File

@ -1,5 +1,5 @@
module.exports = [
[/Circular reexports "\.\/c2.js"\.something --> "\.\/c1.js"\.something -\(circular\)-> "\.\/c2.js"\.something/],
[/Circular reexports "\.\/a.js"\.something -\(circular\)-> "\.\/a.js"\.something/],
[/Circular reexports "\.\/b.js"\.other --> "\.\/b.js"\.something -\(circular\)-> "\.\/b.js"\.other/],
[/Circular reexports "\.\/c2.js"\.something --> "\.\/c1.js"\.something -\(circular\)-> "\.\/c2.js"\.something/]
];