mirror of https://github.com/webpack/webpack.git
fix(css): avoid extra `module.export` output for css module (#19265)
This commit is contained in:
parent
e5c3f95b84
commit
e0891eeea0
|
|
@ -105,6 +105,7 @@ const makeSerializable = require("./util/makeSerializable");
|
||||||
* @property {boolean=} async
|
* @property {boolean=} async
|
||||||
* @property {boolean=} sideEffectFree
|
* @property {boolean=} sideEffectFree
|
||||||
* @property {Record<string, string>=} exportsFinalName
|
* @property {Record<string, string>=} exportsFinalName
|
||||||
|
* @property {boolean=} isCSSModule
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,11 @@ const ASSET_AND_JS_AND_CSS_URL_TYPES = new Set([
|
||||||
"css-url"
|
"css-url"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {"javascript"}
|
||||||
|
*/
|
||||||
|
const JS_TYPE = "javascript";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {ReadonlySet<"javascript">}
|
* @type {ReadonlySet<"javascript">}
|
||||||
*/
|
*/
|
||||||
|
|
@ -54,6 +59,10 @@ const JS_AND_CSS_URL_TYPES = new Set(["javascript", "css-url"]);
|
||||||
*/
|
*/
|
||||||
const JS_AND_CSS_TYPES = new Set(["javascript", "css"]);
|
const JS_AND_CSS_TYPES = new Set(["javascript", "css"]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {"css"}
|
||||||
|
*/
|
||||||
|
const CSS_TYPE = "css";
|
||||||
/**
|
/**
|
||||||
* @type {ReadonlySet<"css">}
|
* @type {ReadonlySet<"css">}
|
||||||
*/
|
*/
|
||||||
|
|
@ -94,6 +103,7 @@ const CONSUME_SHARED_TYPES = new Set(["consume-shared"]);
|
||||||
const SHARED_INIT_TYPES = new Set(["share-init"]);
|
const SHARED_INIT_TYPES = new Set(["share-init"]);
|
||||||
|
|
||||||
module.exports.NO_TYPES = NO_TYPES;
|
module.exports.NO_TYPES = NO_TYPES;
|
||||||
|
module.exports.JS_TYPE = JS_TYPE;
|
||||||
module.exports.JS_TYPES = JS_TYPES;
|
module.exports.JS_TYPES = JS_TYPES;
|
||||||
module.exports.JS_AND_CSS_TYPES = JS_AND_CSS_TYPES;
|
module.exports.JS_AND_CSS_TYPES = JS_AND_CSS_TYPES;
|
||||||
module.exports.JS_AND_CSS_URL_TYPES = JS_AND_CSS_URL_TYPES;
|
module.exports.JS_AND_CSS_URL_TYPES = JS_AND_CSS_URL_TYPES;
|
||||||
|
|
@ -102,6 +112,7 @@ module.exports.ASSET_TYPES = ASSET_TYPES;
|
||||||
module.exports.ASSET_AND_JS_TYPES = ASSET_AND_JS_TYPES;
|
module.exports.ASSET_AND_JS_TYPES = ASSET_AND_JS_TYPES;
|
||||||
module.exports.ASSET_AND_CSS_URL_TYPES = ASSET_AND_CSS_URL_TYPES;
|
module.exports.ASSET_AND_CSS_URL_TYPES = ASSET_AND_CSS_URL_TYPES;
|
||||||
module.exports.ASSET_AND_JS_AND_CSS_URL_TYPES = ASSET_AND_JS_AND_CSS_URL_TYPES;
|
module.exports.ASSET_AND_JS_AND_CSS_URL_TYPES = ASSET_AND_JS_AND_CSS_URL_TYPES;
|
||||||
|
module.exports.CSS_TYPE = CSS_TYPE;
|
||||||
module.exports.CSS_TYPES = CSS_TYPES;
|
module.exports.CSS_TYPES = CSS_TYPES;
|
||||||
module.exports.CSS_URL_TYPES = CSS_URL_TYPES;
|
module.exports.CSS_URL_TYPES = CSS_URL_TYPES;
|
||||||
module.exports.CSS_IMPORT_TYPES = CSS_IMPORT_TYPES;
|
module.exports.CSS_IMPORT_TYPES = CSS_IMPORT_TYPES;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,10 @@ const Generator = require("../Generator");
|
||||||
const InitFragment = require("../InitFragment");
|
const InitFragment = require("../InitFragment");
|
||||||
const {
|
const {
|
||||||
JS_AND_CSS_EXPORT_TYPES,
|
JS_AND_CSS_EXPORT_TYPES,
|
||||||
JS_AND_CSS_TYPES
|
JS_AND_CSS_TYPES,
|
||||||
|
CSS_TYPES,
|
||||||
|
JS_TYPE,
|
||||||
|
CSS_TYPE
|
||||||
} = require("../ModuleSourceTypesConstants");
|
} = require("../ModuleSourceTypesConstants");
|
||||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||||
const Template = require("../Template");
|
const Template = require("../Template");
|
||||||
|
|
@ -27,21 +30,25 @@ const Template = require("../Template");
|
||||||
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
|
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
|
||||||
/** @typedef {import("../Generator").UpdateHashContext} UpdateHashContext */
|
/** @typedef {import("../Generator").UpdateHashContext} UpdateHashContext */
|
||||||
/** @typedef {import("../Module").BuildInfo} BuildInfo */
|
/** @typedef {import("../Module").BuildInfo} BuildInfo */
|
||||||
|
/** @typedef {import("../Module").BuildMeta} BuildMeta */
|
||||||
/** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
|
/** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
|
||||||
/** @typedef {import("../Module").SourceTypes} SourceTypes */
|
/** @typedef {import("../Module").SourceTypes} SourceTypes */
|
||||||
|
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
||||||
/** @typedef {import("../NormalModule")} NormalModule */
|
/** @typedef {import("../NormalModule")} NormalModule */
|
||||||
/** @typedef {import("../util/Hash")} Hash */
|
/** @typedef {import("../util/Hash")} Hash */
|
||||||
|
|
||||||
class CssGenerator extends Generator {
|
class CssGenerator extends Generator {
|
||||||
/**
|
/**
|
||||||
* @param {CssAutoGeneratorOptions | CssGlobalGeneratorOptions | CssModuleGeneratorOptions} options options
|
* @param {CssAutoGeneratorOptions | CssGlobalGeneratorOptions | CssModuleGeneratorOptions} options options
|
||||||
|
* @param {ModuleGraph} moduleGraph the module graph
|
||||||
*/
|
*/
|
||||||
constructor(options) {
|
constructor(options, moduleGraph) {
|
||||||
super();
|
super();
|
||||||
this.convention = options.exportsConvention;
|
this.convention = options.exportsConvention;
|
||||||
this.localIdentName = options.localIdentName;
|
this.localIdentName = options.localIdentName;
|
||||||
this.exportsOnly = options.exportsOnly;
|
this.exportsOnly = options.exportsOnly;
|
||||||
this.esModule = options.esModule;
|
this.esModule = options.esModule;
|
||||||
|
this._moduleGraph = moduleGraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -169,6 +176,13 @@ class CssGenerator extends Generator {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
cssData.exports.size === 0 &&
|
||||||
|
!(/** @type {BuildMeta} */ (module.buildMeta).isCSSModule)
|
||||||
|
) {
|
||||||
|
return new RawSource("");
|
||||||
|
}
|
||||||
|
|
||||||
const needNsObj =
|
const needNsObj =
|
||||||
this.esModule &&
|
this.esModule &&
|
||||||
generateContext.moduleGraph
|
generateContext.moduleGraph
|
||||||
|
|
@ -237,7 +251,22 @@ class CssGenerator extends Generator {
|
||||||
*/
|
*/
|
||||||
getTypes(module) {
|
getTypes(module) {
|
||||||
// TODO, find a better way to prevent the original module from being removed after concatenation, maybe it is a bug
|
// TODO, find a better way to prevent the original module from being removed after concatenation, maybe it is a bug
|
||||||
return this.exportsOnly ? JS_AND_CSS_EXPORT_TYPES : JS_AND_CSS_TYPES;
|
if (this.exportsOnly) {
|
||||||
|
return JS_AND_CSS_EXPORT_TYPES;
|
||||||
|
}
|
||||||
|
const sourceTypes = new Set();
|
||||||
|
const connections = this._moduleGraph.getIncomingConnections(module);
|
||||||
|
for (const connection of connections) {
|
||||||
|
if (!connection.originModule) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (connection.originModule.type.split("/")[0] !== CSS_TYPE)
|
||||||
|
sourceTypes.add(JS_TYPE);
|
||||||
|
}
|
||||||
|
if (sourceTypes.has(JS_TYPE)) {
|
||||||
|
return JS_AND_CSS_TYPES;
|
||||||
|
}
|
||||||
|
return CSS_TYPES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -248,12 +277,17 @@ class CssGenerator extends Generator {
|
||||||
getSize(module, type) {
|
getSize(module, type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "javascript": {
|
case "javascript": {
|
||||||
const buildInfo = /** @type {BuildInfo} */ (module.buildInfo);
|
const cssData = /** @type {BuildInfo} */ (module.buildInfo).cssData;
|
||||||
if (!buildInfo.cssData) {
|
if (!cssData) {
|
||||||
return 42;
|
return 42;
|
||||||
}
|
}
|
||||||
|
if (cssData.exports.size === 0) {
|
||||||
const exports = buildInfo.cssData.exports;
|
if (/** @type {BuildMeta} */ (module.buildMeta).isCSSModule) {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const exports = cssData.exports;
|
||||||
const stringifiedExports = JSON.stringify(
|
const stringifiedExports = JSON.stringify(
|
||||||
Array.from(exports).reduce((obj, [key, value]) => {
|
Array.from(exports).reduce((obj, [key, value]) => {
|
||||||
obj[key] = value;
|
obj[key] = value;
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,10 @@ class CssModulesPlugin {
|
||||||
.tap(PLUGIN_NAME, generatorOptions => {
|
.tap(PLUGIN_NAME, generatorOptions => {
|
||||||
validateGeneratorOptions[type](generatorOptions);
|
validateGeneratorOptions[type](generatorOptions);
|
||||||
|
|
||||||
return new CssGenerator(generatorOptions);
|
return new CssGenerator(
|
||||||
|
generatorOptions,
|
||||||
|
compilation.moduleGraph
|
||||||
|
);
|
||||||
});
|
});
|
||||||
normalModuleFactory.hooks.createModuleClass
|
normalModuleFactory.hooks.createModuleClass
|
||||||
.for(type)
|
.for(type)
|
||||||
|
|
|
||||||
|
|
@ -361,6 +361,9 @@ class CssParser extends Parser {
|
||||||
|
|
||||||
const isModules = mode === "global" || mode === "local";
|
const isModules = mode === "global" || mode === "local";
|
||||||
|
|
||||||
|
/** @type {BuildMeta} */
|
||||||
|
(module.buildMeta).isCSSModule = isModules;
|
||||||
|
|
||||||
const locConverter = new LocConverter(source);
|
const locConverter = new LocConverter(source);
|
||||||
|
|
||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
const asyncLib = require("neo-async");
|
const asyncLib = require("neo-async");
|
||||||
const ChunkGraph = require("../ChunkGraph");
|
const ChunkGraph = require("../ChunkGraph");
|
||||||
const ModuleGraph = require("../ModuleGraph");
|
const ModuleGraph = require("../ModuleGraph");
|
||||||
|
const { JS_TYPE } = require("../ModuleSourceTypesConstants");
|
||||||
const { STAGE_DEFAULT } = require("../OptimizationStages");
|
const { STAGE_DEFAULT } = require("../OptimizationStages");
|
||||||
const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
|
const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
|
||||||
const { compareModulesByIdentifier } = require("../util/comparators");
|
const { compareModulesByIdentifier } = require("../util/comparators");
|
||||||
|
|
@ -452,7 +453,7 @@ class ModuleConcatenationPlugin {
|
||||||
chunkGraph.disconnectChunkAndModule(chunk, m);
|
chunkGraph.disconnectChunkAndModule(chunk, m);
|
||||||
} else {
|
} else {
|
||||||
const newSourceTypes = new Set(sourceTypes);
|
const newSourceTypes = new Set(sourceTypes);
|
||||||
newSourceTypes.delete("javascript");
|
newSourceTypes.delete(JS_TYPE);
|
||||||
chunkGraph.setChunkModuleSourceTypes(
|
chunkGraph.setChunkModuleSourceTypes(
|
||||||
chunk,
|
chunk,
|
||||||
m,
|
m,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const vm = require("vm");
|
||||||
const rimraf = require("rimraf");
|
const rimraf = require("rimraf");
|
||||||
const checkArrayExpectation = require("./checkArrayExpectation");
|
const checkArrayExpectation = require("./checkArrayExpectation");
|
||||||
const createLazyTestEnv = require("./helpers/createLazyTestEnv");
|
const createLazyTestEnv = require("./helpers/createLazyTestEnv");
|
||||||
|
const FakeDocument = require("./helpers/FakeDocument");
|
||||||
|
|
||||||
const casesPath = path.join(__dirname, "hotCases");
|
const casesPath = path.join(__dirname, "hotCases");
|
||||||
let categories = fs
|
let categories = fs
|
||||||
|
|
@ -108,8 +109,7 @@ const describeCases = config => {
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler = webpack(options);
|
const onCompiled = (err, stats) => {
|
||||||
compiler.run((err, stats) => {
|
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const jsonStats = stats.toJson({
|
const jsonStats = stats.toJson({
|
||||||
errorDetails: true
|
errorDetails: true
|
||||||
|
|
@ -179,9 +179,8 @@ const describeCases = config => {
|
||||||
},
|
},
|
||||||
document: {
|
document: {
|
||||||
createElement(type) {
|
createElement(type) {
|
||||||
return {
|
const ele = {
|
||||||
_type: type,
|
_type: type,
|
||||||
sheet: {},
|
|
||||||
getAttribute(name) {
|
getAttribute(name) {
|
||||||
return this[name];
|
return this[name];
|
||||||
},
|
},
|
||||||
|
|
@ -199,6 +198,11 @@ const describeCases = config => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
ele.sheet =
|
||||||
|
type === "link"
|
||||||
|
? new FakeDocument.FakeSheet(ele, outputDirectory)
|
||||||
|
: {};
|
||||||
|
return ele;
|
||||||
},
|
},
|
||||||
head: {
|
head: {
|
||||||
appendChild(element) {
|
appendChild(element) {
|
||||||
|
|
@ -353,8 +357,15 @@ const describeCases = config => {
|
||||||
let promise = Promise.resolve();
|
let promise = Promise.resolve();
|
||||||
const info = stats.toJson({ all: false, entrypoints: true });
|
const info = stats.toJson({ all: false, entrypoints: true });
|
||||||
if (config.target === "web") {
|
if (config.target === "web") {
|
||||||
for (const file of info.entrypoints.main.assets)
|
for (const file of info.entrypoints.main.assets) {
|
||||||
|
if (file.name.endsWith(".css")) {
|
||||||
|
const link = window.document.createElement("link");
|
||||||
|
link.href = path.join(outputDirectory, file.name);
|
||||||
|
window.document.head.appendChild(link);
|
||||||
|
} else {
|
||||||
_require(`./${file.name}`);
|
_require(`./${file.name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const assets = info.entrypoints.main.assets;
|
const assets = info.entrypoints.main.assets;
|
||||||
const result = _require(
|
const result = _require(
|
||||||
|
|
@ -375,7 +386,9 @@ const describeCases = config => {
|
||||||
done(err);
|
done(err);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
compiler = webpack(options);
|
||||||
|
compiler.run(onCompiled);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
it("should compile and load style on demand", (done) => {
|
it("should compile and load style on demand", (done) => {
|
||||||
import("./style.css").then(x => {
|
import("./style.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
const style = getComputedStyle(document.body);
|
const style = getComputedStyle(document.body);
|
||||||
expect(style.getPropertyValue("background")).toBe(" red");
|
expect(style.getPropertyValue("background")).toBe(" red");
|
||||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import * as style from "./style.css";
|
import * as style from "./style.css";
|
||||||
|
|
||||||
it("should compile and load style on demand", done => {
|
it("should compile and load style on demand", done => {
|
||||||
expect(style).toEqual(nsObj({}));
|
expect(style).toEqual({});
|
||||||
import("./style2.css").then(x => {
|
import("./style2.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
done();
|
done();
|
||||||
}, done);
|
}, done);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import * as style from "./style.css";
|
import * as style from "./style.css";
|
||||||
|
|
||||||
it("should compile and load style on demand", done => {
|
it("should compile and load style on demand", done => {
|
||||||
expect(style).toEqual(nsObj({}));
|
expect(style).toEqual({});
|
||||||
import("./style2.css").then(x => {
|
import("./style2.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
const style = getComputedStyle(document.body);
|
const style = getComputedStyle(document.body);
|
||||||
expect(style.getPropertyValue("background")).toBe(" red");
|
expect(style.getPropertyValue("background")).toBe(" red");
|
||||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import * as style from "./style.css";
|
import * as style from "./style.css";
|
||||||
|
|
||||||
it("should compile and load initial style", () => {
|
it("should compile and load initial style", () => {
|
||||||
expect(style).toEqual(nsObj({}));
|
expect(style).toEqual({});
|
||||||
const computedStyle = getComputedStyle(document.body);
|
const computedStyle = getComputedStyle(document.body);
|
||||||
expect(computedStyle.getPropertyValue("background")).toBe(" red");
|
expect(computedStyle.getPropertyValue("background")).toBe(" red");
|
||||||
expect(computedStyle.getPropertyValue("margin")).toBe(" 10px");
|
expect(computedStyle.getPropertyValue("margin")).toBe(" 10px");
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import * as style from "./style.css";
|
import * as style from "./style.css";
|
||||||
|
|
||||||
it("should compile and load style on demand", done => {
|
it("should compile and load style on demand", done => {
|
||||||
expect(style).toEqual(nsObj({}));
|
expect(style).toEqual({});
|
||||||
import("./style2.css").then(x => {
|
import("./style2.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
const style = getComputedStyle(document.body);
|
const style = getComputedStyle(document.body);
|
||||||
expect(style.getPropertyValue("background")).toBe(" red");
|
expect(style.getPropertyValue("background")).toBe(" red");
|
||||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import * as style from "./style.css";
|
import * as style from "./style.css";
|
||||||
|
|
||||||
it("should compile and load style on demand", done => {
|
it("should compile and load style on demand", done => {
|
||||||
expect(style).toEqual(nsObj({}));
|
expect(style).toEqual({});
|
||||||
import("./style2.css").then(x => {
|
import("./style2.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
const style = getComputedStyle(document.body);
|
const style = getComputedStyle(document.body);
|
||||||
expect(style.getPropertyValue("background")).toBe(" red");
|
expect(style.getPropertyValue("background")).toBe(" red");
|
||||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ it("should work with js", done => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should work with css", done => {
|
it("should work with css", done => {
|
||||||
expect(style).toEqual(nsObj({}));
|
expect(style).toEqual({});
|
||||||
|
|
||||||
const computedStyle = getComputedStyle(document.body);
|
const computedStyle = getComputedStyle(document.body);
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ it("should work with css", done => {
|
||||||
expect(computedStyle.getPropertyValue("color")).toBe(" yellow");
|
expect(computedStyle.getPropertyValue("color")).toBe(" yellow");
|
||||||
|
|
||||||
import("./async.css").then(x => {
|
import("./async.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
|
|
||||||
const style = getComputedStyle(document.body);
|
const style = getComputedStyle(document.body);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
it("should import an external css", done => {
|
it("should import an external css", done => {
|
||||||
import("../external/style.css").then(x => {
|
import("../external/style.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
done();
|
done();
|
||||||
}, done);
|
}, done);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
it("should import an external css", done => {
|
it("should import an external css", done => {
|
||||||
import("./style.css").then(x => {
|
import("./style.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
const style = getComputedStyle(document.body);
|
const style = getComputedStyle(document.body);
|
||||||
expect(style.getPropertyValue("color")).toBe(" green");
|
expect(style.getPropertyValue("color")).toBe(" green");
|
||||||
expect(style.getPropertyValue("background")).toBe(
|
expect(style.getPropertyValue("background")).toBe(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import * as style from "./style.css";
|
import * as style from "./style.css";
|
||||||
|
|
||||||
it("should compile and load style on demand", () => {
|
it("should compile and load style on demand", () => {
|
||||||
expect(style).toEqual(nsObj({}));
|
expect(style).toEqual({});
|
||||||
const computedStyle = getComputedStyle(document.body);
|
const computedStyle = getComputedStyle(document.body);
|
||||||
expect(computedStyle.getPropertyValue("background")).toBe(" red");
|
expect(computedStyle.getPropertyValue("background")).toBe(" red");
|
||||||
expect(computedStyle.getPropertyValue("margin")).toBe(" 10px");
|
expect(computedStyle.getPropertyValue("margin")).toBe(" 10px");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.bar {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.bar {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.bar {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.bar {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.bar {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url("./a1.css");
|
||||||
|
|
||||||
|
.foo {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
import "./main.css"
|
||||||
|
require("./a2.css")
|
||||||
|
import("./a2.css").then(() => {})
|
||||||
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
import a1 from "./a1.module.css"
|
||||||
|
const a2 = require("./a2.module.css")
|
||||||
|
import("./a3.module.css").then(() => {})
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
module.exports = {
|
||||||
|
findBundle: function (i) {
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
return ["test.js"];
|
||||||
|
case 1:
|
||||||
|
return ["test.js", `1/main.js`];
|
||||||
|
case 2:
|
||||||
|
return ["test.js", `2/main.js`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
it("should work", () => {
|
||||||
|
const stats = __STATS__.children[__STATS_I__];
|
||||||
|
|
||||||
|
expect(stats.assets.findIndex(a => a.name === "test.js") > -1).toBe(true);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
stats.assets.findIndex(a => a.name === `${__STATS_I__}/main.css`) > -1
|
||||||
|
).toBe(true);
|
||||||
|
|
||||||
|
if (__STATS_I__ === 0) {
|
||||||
|
// ./main.css
|
||||||
|
// ./a.css
|
||||||
|
// and it still output two runtime module:
|
||||||
|
// 'webpack/runtime/make namespace object'
|
||||||
|
// 'webpack/runtime/css loading'
|
||||||
|
expect(stats.modules.length).toBe(4);
|
||||||
|
} else if (__STATS_I__ === 1) {
|
||||||
|
stats.modules
|
||||||
|
.filter(module => module.moduleType === "css/auto")
|
||||||
|
.forEach(module => {
|
||||||
|
expect(module.sizes["javascript"] === 1).toBe(true);
|
||||||
|
});
|
||||||
|
} else if (__STATS_I__ === 2) {
|
||||||
|
stats.modules
|
||||||
|
.filter(module => module.moduleType === "css/auto")
|
||||||
|
.forEach(module => {
|
||||||
|
expect(module.sizes["javascript"] === 1).toBe(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
const webpack = require("../../../../");
|
||||||
|
|
||||||
|
const entry = i => {
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
return {
|
||||||
|
main: ["./main.css"]
|
||||||
|
};
|
||||||
|
case 1:
|
||||||
|
return {
|
||||||
|
main: ["./main1.js"]
|
||||||
|
};
|
||||||
|
case 2:
|
||||||
|
return {
|
||||||
|
main: ["./main2.js"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} i param
|
||||||
|
* @returns {import("../../../../").Configuration} return
|
||||||
|
*/
|
||||||
|
const common = i => ({
|
||||||
|
entry: {
|
||||||
|
...entry(i)
|
||||||
|
},
|
||||||
|
target: "web",
|
||||||
|
devtool: false,
|
||||||
|
experiments: {
|
||||||
|
css: true
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: `${i}/[name].js`,
|
||||||
|
chunkFilename: `${i}/[name].js`,
|
||||||
|
cssFilename: `${i}/[name].css`,
|
||||||
|
cssChunkFilename: `${i}/[name].css`
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @type {import("../../../../").Configuration[]} */
|
||||||
|
module.exports = [...[0, 1].map(i => common(i))];
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import * as style from "./style.css";
|
import * as style from "./style.css";
|
||||||
|
|
||||||
it("should compile and load style on demand", done => {
|
it("should compile and load style on demand", done => {
|
||||||
expect(style).toEqual(nsObj({}));
|
expect(style).toEqual({});
|
||||||
import("./style2.css").then(x => {
|
import("./style2.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
const style = getComputedStyle(document.body);
|
const style = getComputedStyle(document.body);
|
||||||
expect(style.getPropertyValue("background")).toBe(" red");
|
expect(style.getPropertyValue("background")).toBe(" red");
|
||||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import * as styles1 from "./style.less";
|
||||||
import * as styles2 from "./style.modules.less";
|
import * as styles2 from "./style.modules.less";
|
||||||
|
|
||||||
it("should prefer relative", () => {
|
it("should prefer relative", () => {
|
||||||
expect(styles1).toEqual(nsObj({}));
|
expect(styles1).toEqual({});
|
||||||
expect(styles2).toEqual(nsObj({
|
expect(styles2).toEqual(nsObj({
|
||||||
"style-module": "_style_modules_less-style-module",
|
"style-module": "_style_modules_less-style-module",
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import * as styles1 from "./style.css";
|
||||||
import * as styles2 from "./style.modules.css";
|
import * as styles2 from "./style.modules.css";
|
||||||
|
|
||||||
it("should prefer relative", () => {
|
it("should prefer relative", () => {
|
||||||
expect(styles1).toEqual(nsObj({}));
|
expect(styles1).toEqual({});
|
||||||
expect(styles2).toEqual(nsObj({
|
expect(styles2).toEqual(nsObj({
|
||||||
"style-module": "_style_modules_css-style-module",
|
"style-module": "_style_modules_css-style-module",
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ import * as pureStyle from "./style.css";
|
||||||
import * as styles from "./style.modules.css";
|
import * as styles from "./style.modules.css";
|
||||||
|
|
||||||
it("should work", done => {
|
it("should work", done => {
|
||||||
expect(pureStyle).toEqual(nsObj({}));
|
expect(pureStyle).toEqual({});
|
||||||
const style = getComputedStyle(document.body);
|
const style = getComputedStyle(document.body);
|
||||||
expect(style.getPropertyValue("background")).toBe(" red");
|
expect(style.getPropertyValue("background")).toBe(" red");
|
||||||
expect(styles.foo).toBe('_style_modules_css-foo');
|
expect(styles.foo).toBe('_style_modules_css-foo');
|
||||||
|
|
||||||
import(/* webpackPrefetch: true */ "./style2.css").then(x => {
|
import(/* webpackPrefetch: true */ "./style2.css").then(x => {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
const style = getComputedStyle(document.body);
|
const style = getComputedStyle(document.body);
|
||||||
expect(style.getPropertyValue("color")).toBe(" blue");
|
expect(style.getPropertyValue("color")).toBe(" blue");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ it(`should generate correct url public path with css filename`, done => {
|
||||||
document.body.appendChild(h1);
|
document.body.appendChild(h1);
|
||||||
import("./index.css").then(x => {
|
import("./index.css").then(x => {
|
||||||
try {
|
try {
|
||||||
expect(x).toEqual(nsObj({}));
|
expect(x).toEqual({});
|
||||||
const style1 = getComputedStyle(h1);
|
const style1 = getComputedStyle(h1);
|
||||||
expect(style1).toMatchSnapshot();
|
expect(style1).toMatchSnapshot();
|
||||||
const style2 = getComputedStyle(h2);
|
const style2 = getComputedStyle(h2);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ function getPropertyValue(property) {
|
||||||
return this[property];
|
return this[property];
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = class FakeDocument {
|
class FakeDocument {
|
||||||
constructor(basePath) {
|
constructor(basePath) {
|
||||||
this.head = this.createElement("head");
|
this.head = this.createElement("head");
|
||||||
this.body = this.createElement("body");
|
this.body = this.createElement("body");
|
||||||
|
|
@ -54,7 +54,7 @@ module.exports = class FakeDocument {
|
||||||
}
|
}
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
class FakeElement {
|
class FakeElement {
|
||||||
constructor(document, type, basePath) {
|
constructor(document, type, basePath) {
|
||||||
|
|
@ -252,3 +252,8 @@ class FakeSheet {
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FakeDocument.FakeSheet = FakeSheet;
|
||||||
|
FakeDocument.FakeElement = FakeDocument;
|
||||||
|
|
||||||
|
module.exports = FakeDocument;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
.html {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
@import url("./a.css");
|
||||||
|
---
|
||||||
|
html {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
html {
|
||||||
|
color: yellow;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
it("should work", done => {
|
||||||
|
const links = window.document.getElementsByTagName("link");
|
||||||
|
expect(links[0].sheet.css).toContain("color: green;");
|
||||||
|
|
||||||
|
NEXT(
|
||||||
|
require("../../update")(done, true, () => {
|
||||||
|
const links = window.document.getElementsByTagName("link");
|
||||||
|
expect(links[0].sheet.css).toContain("color: blue;");
|
||||||
|
|
||||||
|
NEXT(
|
||||||
|
require("../../update")(done, true, () => {
|
||||||
|
const links = window.document.getElementsByTagName("link");
|
||||||
|
expect(links[0].sheet.css).toContain("color: yellow;");
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = function (config) {
|
||||||
|
if (config.target !== "web") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
/** @type {import("../../../../").Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
mode: "development",
|
||||||
|
devtool: false,
|
||||||
|
experiments: {
|
||||||
|
css: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
.html {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
html {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
html {
|
||||||
|
color: yellow;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
it("should work", done => {
|
||||||
|
const links = window.document.getElementsByTagName("link");
|
||||||
|
expect(links[0].sheet.css).toContain("color: red;");
|
||||||
|
|
||||||
|
NEXT(
|
||||||
|
require("../../update")(done, true, () => {
|
||||||
|
const links = window.document.getElementsByTagName("link");
|
||||||
|
expect(links[0].sheet.css).toContain("color: blue;");
|
||||||
|
|
||||||
|
NEXT(
|
||||||
|
require("../../update")(done, true, () => {
|
||||||
|
const links = window.document.getElementsByTagName("link");
|
||||||
|
expect(links[0].sheet.css).toContain("color: yellow;");
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = function (config) {
|
||||||
|
if (config.target !== "web") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
const webpack = require("../../../../");
|
||||||
|
|
||||||
|
/** @type {import("../../../../").Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
mode: "development",
|
||||||
|
devtool: false,
|
||||||
|
entry: ["./index.js", "./index.css"],
|
||||||
|
experiments: {
|
||||||
|
css: true
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
apply(compiler) {
|
||||||
|
compiler.hooks.compilation.tap("Test", compilation => {
|
||||||
|
compilation.hooks.additionalTreeRuntimeRequirements.tap(
|
||||||
|
"Test",
|
||||||
|
(module, set, context) => {
|
||||||
|
// To prevent the runtime error `ReferenceError: __webpack_exports__ is not defined`,
|
||||||
|
// which occurs because the default `output.library` setting is `commonjs2`,
|
||||||
|
// resulting in adding `module.exports = __webpack_exports__;`.
|
||||||
|
set.add(webpack.RuntimeGlobals.startup);
|
||||||
|
set.add(webpack.RuntimeGlobals.exports);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
const getFile = name =>
|
||||||
|
__non_webpack_require__("fs").readFileSync(
|
||||||
|
__non_webpack_require__("path").join(__dirname, name),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
|
||||||
|
it("should work", async function (done) {
|
||||||
|
let promise = import("./style.css");
|
||||||
|
|
||||||
|
NEXT(
|
||||||
|
require("../../update")(done, true, () => {
|
||||||
|
promise.then(res => {
|
||||||
|
const links = window.document.getElementsByTagName("link");
|
||||||
|
let href = links[0].href;
|
||||||
|
expect(href).toBe("https://test.cases/path/style_css.css");
|
||||||
|
href = href
|
||||||
|
.replace(/^https:\/\/test\.cases\/path\//, "")
|
||||||
|
.replace(/^https:\/\/example\.com\//, "");
|
||||||
|
let sheet = getFile(href);
|
||||||
|
expect(sheet).toContain("color: red;");
|
||||||
|
|
||||||
|
module.hot.accept("./style.css", () => {
|
||||||
|
const links = window.document.getElementsByTagName("link");
|
||||||
|
let href = links[0].href;
|
||||||
|
expect(href).toContain("https://test.cases/path/style_css.css?hmr");
|
||||||
|
href = href
|
||||||
|
.replace(/^https:\/\/test\.cases\/path\//, "")
|
||||||
|
.replace(/^https:\/\/example\.com\//, "")
|
||||||
|
.split("?")[0];
|
||||||
|
let sheet = getFile(href);
|
||||||
|
expect(sheet).toContain("color: blue;");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
NEXT(require("../../update")(done));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
html {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
html {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
html {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = function (config) {
|
||||||
|
if (config.target !== "web") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
/** @type {import("../../../../").Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
mode: "development",
|
||||||
|
devtool: false,
|
||||||
|
output: {
|
||||||
|
cssFilename: "[name].css",
|
||||||
|
cssChunkFilename: "[name].css"
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
css: true,
|
||||||
|
lazyCompilation: {
|
||||||
|
entries: false,
|
||||||
|
imports: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
__dirname: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -7617,6 +7617,7 @@ declare interface KnownBuildMeta {
|
||||||
async?: boolean;
|
async?: boolean;
|
||||||
sideEffectFree?: boolean;
|
sideEffectFree?: boolean;
|
||||||
exportsFinalName?: Record<string, string>;
|
exportsFinalName?: Record<string, string>;
|
||||||
|
isCSSModule?: boolean;
|
||||||
}
|
}
|
||||||
declare interface KnownCreateStatsOptionsContext {
|
declare interface KnownCreateStatsOptionsContext {
|
||||||
forToString?: boolean;
|
forToString?: boolean;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue