Skip to content

Commit

Permalink
Merge pull request #12871 from webpack/feature/generate-asset
Browse files Browse the repository at this point in the history
add `emit` option for asset modules
  • Loading branch information
sokra committed Mar 11, 2021
2 parents bcf3cb2 + c014665 commit ab74839
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 163 deletions.
34 changes: 12 additions & 22 deletions declarations/WebpackOptions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -705,11 +705,6 @@ export type AssetParserDataUrlFunction = (
source: string | Buffer,
context: {filename: string; module: import("../lib/Module")}
) => boolean;
/**
* Parser options for asset modules.
*/
export type AssetParserOptions = AssetResourceParserOptions &
AssetParserOptionsExtra;
/**
* A Function returning a Promise resolving to a normalized entry.
*/
Expand Down Expand Up @@ -2577,18 +2572,22 @@ export interface AssetParserDataUrlOptions {
maxSize?: number;
}
/**
* Generator options for asset/resource modules.
* Parser options for asset modules.
*/
export interface AssetResourceGeneratorOptions {
export interface AssetParserOptions {
/**
* This is deprecated and has moved to 'parser.filename'.
* The condition for inlining the asset as DataUrl.
*/
filename?: FilenameTemplate;
dataUrlCondition?: AssetParserDataUrlOptions | AssetParserDataUrlFunction;
}
/**
* Parser options for asset/resource modules.
* Generator options for asset/resource modules.
*/
export interface AssetResourceParserOptions {
export interface AssetResourceGeneratorOptions {
/**
* Emit an output asset from this asset module. This can be set to 'false' to omit emitting e. g. for SSR.
*/
emit?: boolean;
/**
* Specifies the filename template of output files on disk. You must **not** specify an absolute path here, but the path may contain folders separated by '/'! The specified path is joined with the value of the 'output.path' option to determine the location on disk.
*/
Expand Down Expand Up @@ -3142,15 +3141,6 @@ export interface WebpackOptionsNormalized {
*/
watchOptions: WatchOptions;
}
/**
* Parser options for asset modules.
*/
export interface AssetParserOptionsExtra {
/**
* The condition for inlining the asset as DataUrl.
*/
dataUrlCondition?: AssetParserDataUrlOptions | AssetParserDataUrlFunction;
}
/**
* If an dependency matches exactly a property of the object, the property value is used as dependency.
*/
Expand Down Expand Up @@ -3227,9 +3217,9 @@ export interface ParserOptionsByModuleTypeKnown {
*/
"asset/inline"?: EmptyParserOptions;
/**
* Parser options for asset/resource modules.
* No parser options are supported for this module type.
*/
"asset/resource"?: AssetResourceParserOptions;
"asset/resource"?: EmptyParserOptions;
/**
* No parser options are supported for this module type.
*/
Expand Down
1 change: 1 addition & 0 deletions lib/Compilation.js
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
this.mainTemplate = new MainTemplate(this.outputOptions, this);
this.chunkTemplate = new ChunkTemplate(this.outputOptions, this);
this.runtimeTemplate = new RuntimeTemplate(
this,
this.outputOptions,
this.requestShortener
);
Expand Down
6 changes: 4 additions & 2 deletions lib/RuntimeTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const { forEachRuntime, subtractRuntime } = require("./util/runtime");
/** @typedef {import("../declarations/WebpackOptions").OutputNormalized} OutputOptions */
/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
/** @typedef {import("./ChunkGraph")} ChunkGraph */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./Dependency")} Dependency */
/** @typedef {import("./Module")} Module */
/** @typedef {import("./ModuleGraph")} ModuleGraph */
Expand Down Expand Up @@ -51,12 +52,13 @@ Module has these incoming connections: ${Array.from(

class RuntimeTemplate {
/**
* @param {Compilation} compilation the compilation
* @param {OutputOptions} outputOptions the compilation output options
* @param {RequestShortener} requestShortener the request shortener
*/
constructor(outputOptions, requestShortener) {
constructor(compilation, outputOptions, requestShortener) {
this.compilation = compilation;
this.outputOptions = outputOptions || {};
/** @type {RequestShortener} */
this.requestShortener = requestShortener;
}

Expand Down
60 changes: 51 additions & 9 deletions lib/asset/AssetGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const path = require("path");
const { RawSource } = require("webpack-sources");
const Generator = require("../Generator");
const RuntimeGlobals = require("../RuntimeGlobals");
const createHash = require("../util/createHash");
const { makePathsRelative } = require("../util/identifier");

/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../../declarations/WebpackOptions").AssetGeneratorOptions} AssetGeneratorOptions */
Expand All @@ -29,11 +31,13 @@ class AssetGenerator extends Generator {
/**
* @param {AssetGeneratorOptions["dataUrl"]=} dataUrlOptions the options for the data url
* @param {string=} filename override for output.assetModuleFilename
* @param {boolean=} emit generate output asset
*/
constructor(dataUrlOptions, filename) {
constructor(dataUrlOptions, filename, emit) {
super();
this.dataUrlOptions = dataUrlOptions;
this.filename = filename;
this.emit = emit;
}

/**
Expand Down Expand Up @@ -107,22 +111,60 @@ class AssetGenerator extends Generator {
)};`
);
} else {
const assetModuleFilename =
this.filename || runtimeTemplate.outputOptions.assetModuleFilename;
const hash = createHash(runtimeTemplate.outputOptions.hashFunction);
if (runtimeTemplate.outputOptions.hashSalt) {
hash.update(runtimeTemplate.outputOptions.hashSalt);
}
hash.update(originalSource.buffer());
const fullHash = /** @type {string} */ (hash.digest(
runtimeTemplate.outputOptions.hashDigest
));
const contentHash = fullHash.slice(
0,
runtimeTemplate.outputOptions.hashDigestLength
);
module.buildInfo.fullContentHash = fullHash;
const sourceFilename = makePathsRelative(
runtimeTemplate.compilation.compiler.context,
module.matchResource || module.resource,
runtimeTemplate.compilation.compiler.root
).replace(/^\.\//, "");
const {
path: filename,
info
} = runtimeTemplate.compilation.getAssetPathWithInfo(
assetModuleFilename,
{
module,
runtime,
filename: sourceFilename,
chunkGraph,
contentHash
}
);
module.buildInfo.filename = filename;
module.buildInfo.assetInfo = {
sourceFilename,
...info
};
if (getData) {
// We did a mistake in some minor version of 5.x
// Now we have to keep it for backward-compat reasons
// TODO webpack 6 remove
// Due to code generation caching module.buildInfo.XXX can't used to store such information
// It need to be stored in the code generation results instead, where it's cached too
// TODO webpack 6 For back-compat reasons we also store in on module.buildInfo
const data = getData();
data.set("fullContentHash", module.buildInfo.fullContentHash);
data.set("filename", module.buildInfo.filename);
data.set("assetInfo", module.buildInfo.assetInfo);
data.set("fullContentHash", fullHash);
data.set("filename", filename);
data.set("assetInfo", info);
}

runtimeRequirements.add(RuntimeGlobals.publicPath); // add __webpack_require__.p

return new RawSource(
`${RuntimeGlobals.module}.exports = ${
RuntimeGlobals.publicPath
} + ${JSON.stringify(module.buildInfo.filename)};`
} + ${JSON.stringify(filename)};`
);
}
}
Expand All @@ -134,7 +176,7 @@ class AssetGenerator extends Generator {
* @returns {Set<string>} available types (do not mutate)
*/
getTypes(module) {
if (module.buildInfo.dataUrl) {
if (module.buildInfo.dataUrl || this.emit === false) {
return JS_TYPES;
} else {
return JS_AND_ASSET_TYPES;
Expand Down
22 changes: 16 additions & 6 deletions lib/asset/AssetModulesPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class AssetModulesPlugin {

const AssetParser = getAssetParser();

return new AssetParser(dataUrlCondition, parserOptions.filename);
return new AssetParser(dataUrlCondition);
});
normalModuleFactory.hooks.createParser
.for("asset/inline")
Expand All @@ -85,7 +85,7 @@ class AssetModulesPlugin {
.tap(plugin, parserOptions => {
const AssetParser = getAssetParser();

return new AssetParser(false, parserOptions.filename);
return new AssetParser(false);
});
normalModuleFactory.hooks.createParser
.for("asset/source")
Expand Down Expand Up @@ -124,7 +124,11 @@ class AssetModulesPlugin {

const AssetGenerator = getAssetGenerator();

return new AssetGenerator(dataUrl, filename);
return new AssetGenerator(
dataUrl,
filename,
generatorOptions.emit !== false
);
});
}
normalModuleFactory.hooks.createGenerator
Expand Down Expand Up @@ -152,11 +156,17 @@ class AssetModulesPlugin {
);
result.push({
render: () => codeGenResult.sources.get(type),
filename: module.buildInfo.filename,
info: module.buildInfo.assetInfo,
filename:
module.buildInfo.filename ||
codeGenResult.data.get("filename"),
info:
module.buildInfo.assetInfo ||
codeGenResult.data.get("assetInfo"),
auxiliary: true,
identifier: `assetModule${chunkGraph.getModuleId(module)}`,
hash: module.buildInfo.fullContentHash
hash:
module.buildInfo.fullContentHash ||
codeGenResult.data.get("fullContentHash")
});
}
}
Expand Down
60 changes: 8 additions & 52 deletions lib/asset/AssetParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
"use strict";

const Parser = require("../Parser");
const createHash = require("../util/createHash");
const { makePathsRelative } = require("../util/identifier");
const AssetGenerator = require("./AssetGenerator");

/** @typedef {import("../../declarations/WebpackOptions").AssetParserOptions} AssetParserOptions */
/** @typedef {import("../Parser").ParserState} ParserState */
Expand All @@ -17,12 +14,10 @@ const AssetGenerator = require("./AssetGenerator");
class AssetParser extends Parser {
/**
* @param {AssetParserOptions["dataUrlCondition"] | boolean} dataUrlCondition condition for inlining as DataUrl
* @param {string=} filename override for output.assetModuleFilename
*/
constructor(dataUrlCondition, filename) {
constructor(dataUrlCondition) {
super();
this.dataUrlCondition = dataUrlCondition;
this.filename = filename;
}

/**
Expand All @@ -34,65 +29,26 @@ class AssetParser extends Parser {
if (typeof source === "object" && !Buffer.isBuffer(source)) {
throw new Error("AssetParser doesn't accept preparsed AST");
}
const { module, compilation } = state;
module.buildInfo.strict = true;
module.buildMeta.exportsType = "default";
state.module.buildInfo.strict = true;
state.module.buildMeta.exportsType = "default";

if (typeof this.dataUrlCondition === "function") {
module.buildInfo.dataUrl = this.dataUrlCondition(source, {
filename: module.matchResource || module.resource,
module: module
state.module.buildInfo.dataUrl = this.dataUrlCondition(source, {
filename: state.module.matchResource || state.module.resource,
module: state.module
});
} else if (typeof this.dataUrlCondition === "boolean") {
module.buildInfo.dataUrl = this.dataUrlCondition;
state.module.buildInfo.dataUrl = this.dataUrlCondition;
} else if (
this.dataUrlCondition &&
typeof this.dataUrlCondition === "object"
) {
module.buildInfo.dataUrl =
state.module.buildInfo.dataUrl =
Buffer.byteLength(source) <= this.dataUrlCondition.maxSize;
} else {
throw new Error("Unexpected dataUrlCondition type");
}

if (!module.buildInfo.dataUrl) {
const outputOptions = compilation.outputOptions;
const assetModuleFilename =
this.filename ||
// TODO webpack 6 remove
(module.generator instanceof AssetGenerator &&
module.generator.filename) ||
outputOptions.assetModuleFilename;
const hash = createHash(outputOptions.hashFunction);
if (outputOptions.hashSalt) {
hash.update(outputOptions.hashSalt);
}
hash.update(source);
const fullHash = /** @type {string} */ (hash.digest(
outputOptions.hashDigest
));
const contentHash = fullHash.slice(0, outputOptions.hashDigestLength);
module.buildInfo.fullContentHash = fullHash;
const sourceFilename = makePathsRelative(
compilation.compiler.context,
module.matchResource || module.resource,
compilation.compiler.root
).replace(/^\.\//, "");
const { path: filename, info } = compilation.getAssetPathWithInfo(
assetModuleFilename,
{
module,
filename: sourceFilename,
contentHash
}
);
module.buildInfo.filename = filename;
module.buildInfo.assetInfo = {
sourceFilename,
...info
};
}

return state;
}
}
Expand Down
Loading

0 comments on commit ab74839

Please sign in to comment.