mirror of https://github.com/webpack/webpack.git
fix: avoid generating extra js file when using asset module as entrypoint
This commit is contained in:
commit
319576720c
|
@ -2287,11 +2287,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
|
|||
this.hooks.failedEntry.call(entry, options, err);
|
||||
return callback(err);
|
||||
}
|
||||
this.hooks.succeedEntry.call(
|
||||
entry,
|
||||
options,
|
||||
/** @type {Module} */ (module)
|
||||
);
|
||||
this.hooks.succeedEntry.call(entry, options, module);
|
||||
return callback(null, module);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const RawModule = require("./RawModule");
|
||||
const EntryDependency = require("./dependencies/EntryDependency");
|
||||
const createSchemaValidation = require("./util/create-schema-validation");
|
||||
|
||||
/** @typedef {import("../declarations/plugins/IgnorePlugin").IgnorePluginOptions} IgnorePluginOptions */
|
||||
|
@ -73,7 +75,23 @@ class IgnorePlugin {
|
|||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.normalModuleFactory.tap("IgnorePlugin", nmf => {
|
||||
nmf.hooks.beforeResolve.tap("IgnorePlugin", this.checkIgnore);
|
||||
nmf.hooks.beforeResolve.tap("IgnorePlugin", resolveData => {
|
||||
const result = this.checkIgnore(resolveData);
|
||||
|
||||
if (
|
||||
result === false &&
|
||||
resolveData.dependencies.length > 0 &&
|
||||
resolveData.dependencies[0] instanceof EntryDependency
|
||||
) {
|
||||
resolveData.ignoredModule = new RawModule(
|
||||
"",
|
||||
"ignored-entry-module",
|
||||
"(ignored-entry-module)"
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
});
|
||||
compiler.hooks.contextModuleFactory.tap("IgnorePlugin", cmf => {
|
||||
cmf.hooks.beforeResolve.tap("IgnorePlugin", this.checkIgnore);
|
||||
|
|
|
@ -68,6 +68,7 @@ const {
|
|||
* @property {LazySet<string>} fileDependencies
|
||||
* @property {LazySet<string>} missingDependencies
|
||||
* @property {LazySet<string>} contextDependencies
|
||||
* @property {Module=} ignoredModule
|
||||
* @property {boolean} cacheable allow to use the unsafe cache
|
||||
*/
|
||||
|
||||
|
@ -885,12 +886,19 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
|
||||
// Ignored
|
||||
if (result === false) {
|
||||
return callback(null, {
|
||||
/** @type {ModuleFactoryResult} * */
|
||||
const factoryResult = {
|
||||
fileDependencies,
|
||||
missingDependencies,
|
||||
contextDependencies,
|
||||
cacheable: resolveData.cacheable
|
||||
});
|
||||
};
|
||||
|
||||
if (resolveData.ignoredModule) {
|
||||
factoryResult.module = resolveData.ignoredModule;
|
||||
}
|
||||
|
||||
return callback(null, factoryResult);
|
||||
}
|
||||
|
||||
if (typeof result === "object")
|
||||
|
@ -911,6 +919,7 @@ class NormalModuleFactory extends ModuleFactory {
|
|||
});
|
||||
}
|
||||
|
||||
/** @type {ModuleFactoryResult} * */
|
||||
const factoryResult = {
|
||||
module,
|
||||
fileDependencies,
|
||||
|
|
|
@ -78,6 +78,25 @@ const chunkHasJs = (chunk, chunkGraph) => {
|
|||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk a chunk
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @returns {boolean} true, when a JS file is needed for this chunk
|
||||
*/
|
||||
const chunkHasRuntimeOrJs = (chunk, chunkGraph) => {
|
||||
if (
|
||||
chunkGraph.getChunkModulesIterableBySourceType(
|
||||
chunk,
|
||||
WEBPACK_MODULE_TYPE_RUNTIME
|
||||
)
|
||||
)
|
||||
return true;
|
||||
|
||||
return Boolean(
|
||||
chunkGraph.getChunkModulesIterableBySourceType(chunk, "javascript")
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Module} module a module
|
||||
* @param {string} code the code
|
||||
|
@ -271,13 +290,14 @@ class JavascriptModulesPlugin {
|
|||
} = options;
|
||||
|
||||
const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
|
||||
|
||||
let render;
|
||||
const filenameTemplate =
|
||||
JavascriptModulesPlugin.getChunkFilenameTemplate(
|
||||
chunk,
|
||||
outputOptions
|
||||
);
|
||||
|
||||
let render;
|
||||
|
||||
if (hotUpdateChunk) {
|
||||
render = () =>
|
||||
this.renderChunk(
|
||||
|
@ -293,6 +313,10 @@ class JavascriptModulesPlugin {
|
|||
hooks
|
||||
);
|
||||
} else if (chunk.hasRuntime()) {
|
||||
if (!chunkHasRuntimeOrJs(chunk, chunkGraph)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
render = () =>
|
||||
this.renderMain(
|
||||
{
|
||||
|
@ -1149,6 +1173,10 @@ class JavascriptModulesPlugin {
|
|||
entryModule,
|
||||
entrypoint
|
||||
] of chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)) {
|
||||
if (!chunkGraph.getModuleSourceTypes(entryModule).has("javascript")) {
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
const chunks =
|
||||
/** @type {Entrypoint} */
|
||||
(entrypoint).chunks.filter(c => c !== chunk);
|
||||
|
|
|
@ -438,6 +438,7 @@ const describeCases = config => {
|
|||
expect,
|
||||
jest,
|
||||
__STATS__: jsonStats,
|
||||
__STATS_I__: i,
|
||||
nsObj: m => {
|
||||
Object.defineProperty(m, Symbol.toStringTag, {
|
||||
value: "Module"
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.class {
|
||||
background: #000;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
function test() {
|
||||
run();
|
||||
}
|
||||
|
||||
test();
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
findBundle: function (i, options) {
|
||||
return ["test.js"];
|
||||
}
|
||||
};
|
|
@ -0,0 +1,96 @@
|
|||
it("should work", () => {
|
||||
const stats = __STATS__.children[__STATS_I__];
|
||||
|
||||
const test = stats.assets.find(
|
||||
a => a.name === "test.js"
|
||||
);
|
||||
expect(Boolean(test)).toBe(true);
|
||||
|
||||
const assetEntry = stats.assets.find(
|
||||
a => a.info.sourceFilename === "../_images/file.png"
|
||||
);
|
||||
expect(Boolean(assetEntry)).toBe(true);
|
||||
|
||||
switch (__STATS_I__) {
|
||||
case 0: {
|
||||
expect(stats.assets.length).toBe(2);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
expect(stats.assets.length).toBe(3);
|
||||
|
||||
const jsEntry = stats.assets.find(
|
||||
a => a.name.endsWith("js-entry.js")
|
||||
);
|
||||
expect(Boolean(jsEntry)).toBe(true);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
expect(stats.assets.length).toBe(4);
|
||||
|
||||
const cssEntryInJs = stats.assets.find(
|
||||
a => a.name.endsWith("css-entry.js")
|
||||
);
|
||||
expect(Boolean(cssEntryInJs)).toBe(true);
|
||||
|
||||
const cssEntry = stats.assets.find(
|
||||
a => a.name.endsWith("css-entry.css")
|
||||
);
|
||||
expect(Boolean(cssEntry)).toBe(true);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
expect(stats.assets.length).toBe(5);
|
||||
|
||||
const jsEntry = stats.assets.find(
|
||||
a => a.name.endsWith("js-entry.js")
|
||||
);
|
||||
expect(Boolean(jsEntry)).toBe(true);
|
||||
|
||||
const cssEntryInJs = stats.assets.find(
|
||||
a => a.name.endsWith("css-entry.js")
|
||||
);
|
||||
expect(Boolean(cssEntryInJs)).toBe(true);
|
||||
|
||||
const cssEntry = stats.assets.find(
|
||||
a => a.name.endsWith("css-entry.css")
|
||||
);
|
||||
expect(Boolean(cssEntry)).toBe(true);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
expect(stats.assets.length).toBe(4);
|
||||
|
||||
const jsEntry = stats.assets.find(
|
||||
a => a.name.endsWith("js-entry.js")
|
||||
);
|
||||
expect(Boolean(jsEntry)).toBe(true);
|
||||
|
||||
const cssEntryInJs = stats.assets.find(
|
||||
a => a.name.endsWith("css-entry.js")
|
||||
);
|
||||
expect(Boolean(cssEntryInJs)).toBe(true);
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
expect(stats.assets.length).toBe(3);
|
||||
|
||||
const jsEntry = stats.assets.find(
|
||||
a => a.name.endsWith("mixed-entry.js")
|
||||
);
|
||||
expect(Boolean(jsEntry)).toBe(true);
|
||||
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
expect(stats.assets.length).toBe(3);
|
||||
|
||||
const jsEntry = stats.assets.find(
|
||||
a => a.name.endsWith("mixed-entry.js")
|
||||
);
|
||||
expect(Boolean(jsEntry)).toBe(true);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,120 @@
|
|||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const webpack = require("../../../../");
|
||||
|
||||
/** @type {(number, any) => import("../../../../").Configuration} */
|
||||
const common = (i, options) => ({
|
||||
target: "web",
|
||||
output: {
|
||||
filename: `${i}/[name].js`,
|
||||
chunkFilename: `${i}/[name].js`,
|
||||
cssFilename: `${i}/[name].css`,
|
||||
cssChunkFilename: `${i}/[name].css`,
|
||||
assetModuleFilename: `${i}/[name][ext][query]`
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.png$/,
|
||||
type: "asset"
|
||||
}
|
||||
]
|
||||
},
|
||||
experiments: {
|
||||
css: true
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("Test", compilation => {
|
||||
compilation.hooks.processAssets.tap(
|
||||
{
|
||||
name: "copy-webpack-plugin",
|
||||
stage:
|
||||
compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
|
||||
},
|
||||
() => {
|
||||
const data = fs.readFileSync(
|
||||
path.resolve(__dirname, "./test.js")
|
||||
);
|
||||
|
||||
compilation.emitAsset(
|
||||
"test.js",
|
||||
new webpack.sources.RawSource(data)
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
],
|
||||
...options
|
||||
});
|
||||
|
||||
/** @type {import("../../../../").Configuration[]} */
|
||||
module.exports = [
|
||||
common(0, {
|
||||
entry: "../_images/file.png"
|
||||
}),
|
||||
common(1, {
|
||||
entry: {
|
||||
"asset-entry": {
|
||||
import: "../_images/file.png"
|
||||
},
|
||||
"js-entry": {
|
||||
import: "./entry.js"
|
||||
}
|
||||
}
|
||||
}),
|
||||
common(2, {
|
||||
entry: {
|
||||
"asset-entry": {
|
||||
import: "../_images/file.png"
|
||||
},
|
||||
"css-entry": {
|
||||
import: "./entry.css"
|
||||
}
|
||||
}
|
||||
}),
|
||||
common(3, {
|
||||
entry: {
|
||||
"asset-entry": {
|
||||
import: "../_images/file.png"
|
||||
},
|
||||
"js-entry": {
|
||||
import: "./entry.js"
|
||||
},
|
||||
"css-entry": {
|
||||
import: "./entry.css"
|
||||
}
|
||||
}
|
||||
}),
|
||||
common(4, {
|
||||
target: "node",
|
||||
entry: {
|
||||
"asset-entry": {
|
||||
import: "../_images/file.png"
|
||||
},
|
||||
"js-entry": {
|
||||
import: "./entry.js"
|
||||
},
|
||||
"css-entry": {
|
||||
import: "./entry.css"
|
||||
}
|
||||
}
|
||||
}),
|
||||
common(5, {
|
||||
entry: {
|
||||
"mixed-entry": {
|
||||
import: ["./entry.js", "../_images/file.png"]
|
||||
}
|
||||
}
|
||||
}),
|
||||
common(6, {
|
||||
entry: {
|
||||
"mixed-entry": {
|
||||
import: ["../_images/file.png", "./entry.js"]
|
||||
}
|
||||
}
|
||||
})
|
||||
];
|
|
@ -11940,6 +11940,7 @@ declare interface ResolveData {
|
|||
fileDependencies: LazySet<string>;
|
||||
missingDependencies: LazySet<string>;
|
||||
contextDependencies: LazySet<string>;
|
||||
ignoredModule?: Module;
|
||||
|
||||
/**
|
||||
* allow to use the unsafe cache
|
||||
|
|
Loading…
Reference in New Issue