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=} sideEffectFree
|
||||
* @property {Record<string, string>=} exportsFinalName
|
||||
* @property {boolean=} isCSSModule
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ const ASSET_AND_JS_AND_CSS_URL_TYPES = new Set([
|
|||
"css-url"
|
||||
]);
|
||||
|
||||
/**
|
||||
* @type {"javascript"}
|
||||
*/
|
||||
const JS_TYPE = "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"]);
|
||||
|
||||
/**
|
||||
* @type {"css"}
|
||||
*/
|
||||
const CSS_TYPE = "css";
|
||||
/**
|
||||
* @type {ReadonlySet<"css">}
|
||||
*/
|
||||
|
|
@ -94,6 +103,7 @@ const CONSUME_SHARED_TYPES = new Set(["consume-shared"]);
|
|||
const SHARED_INIT_TYPES = new Set(["share-init"]);
|
||||
|
||||
module.exports.NO_TYPES = NO_TYPES;
|
||||
module.exports.JS_TYPE = JS_TYPE;
|
||||
module.exports.JS_TYPES = JS_TYPES;
|
||||
module.exports.JS_AND_CSS_TYPES = JS_AND_CSS_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_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.CSS_TYPE = CSS_TYPE;
|
||||
module.exports.CSS_TYPES = CSS_TYPES;
|
||||
module.exports.CSS_URL_TYPES = CSS_URL_TYPES;
|
||||
module.exports.CSS_IMPORT_TYPES = CSS_IMPORT_TYPES;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ const Generator = require("../Generator");
|
|||
const InitFragment = require("../InitFragment");
|
||||
const {
|
||||
JS_AND_CSS_EXPORT_TYPES,
|
||||
JS_AND_CSS_TYPES
|
||||
JS_AND_CSS_TYPES,
|
||||
CSS_TYPES,
|
||||
JS_TYPE,
|
||||
CSS_TYPE
|
||||
} = require("../ModuleSourceTypesConstants");
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const Template = require("../Template");
|
||||
|
|
@ -27,21 +30,25 @@ const Template = require("../Template");
|
|||
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
|
||||
/** @typedef {import("../Generator").UpdateHashContext} UpdateHashContext */
|
||||
/** @typedef {import("../Module").BuildInfo} BuildInfo */
|
||||
/** @typedef {import("../Module").BuildMeta} BuildMeta */
|
||||
/** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
|
||||
/** @typedef {import("../Module").SourceTypes} SourceTypes */
|
||||
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
||||
/** @typedef {import("../NormalModule")} NormalModule */
|
||||
/** @typedef {import("../util/Hash")} Hash */
|
||||
|
||||
class CssGenerator extends Generator {
|
||||
/**
|
||||
* @param {CssAutoGeneratorOptions | CssGlobalGeneratorOptions | CssModuleGeneratorOptions} options options
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
*/
|
||||
constructor(options) {
|
||||
constructor(options, moduleGraph) {
|
||||
super();
|
||||
this.convention = options.exportsConvention;
|
||||
this.localIdentName = options.localIdentName;
|
||||
this.exportsOnly = options.exportsOnly;
|
||||
this.esModule = options.esModule;
|
||||
this._moduleGraph = moduleGraph;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -169,6 +176,13 @@ class CssGenerator extends Generator {
|
|||
return source;
|
||||
}
|
||||
|
||||
if (
|
||||
cssData.exports.size === 0 &&
|
||||
!(/** @type {BuildMeta} */ (module.buildMeta).isCSSModule)
|
||||
) {
|
||||
return new RawSource("");
|
||||
}
|
||||
|
||||
const needNsObj =
|
||||
this.esModule &&
|
||||
generateContext.moduleGraph
|
||||
|
|
@ -237,7 +251,22 @@ class CssGenerator extends Generator {
|
|||
*/
|
||||
getTypes(module) {
|
||||
// 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) {
|
||||
switch (type) {
|
||||
case "javascript": {
|
||||
const buildInfo = /** @type {BuildInfo} */ (module.buildInfo);
|
||||
if (!buildInfo.cssData) {
|
||||
const cssData = /** @type {BuildInfo} */ (module.buildInfo).cssData;
|
||||
if (!cssData) {
|
||||
return 42;
|
||||
}
|
||||
|
||||
const exports = buildInfo.cssData.exports;
|
||||
if (cssData.exports.size === 0) {
|
||||
if (/** @type {BuildMeta} */ (module.buildMeta).isCSSModule) {
|
||||
return 42;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const exports = cssData.exports;
|
||||
const stringifiedExports = JSON.stringify(
|
||||
Array.from(exports).reduce((obj, [key, value]) => {
|
||||
obj[key] = value;
|
||||
|
|
|
|||
|
|
@ -301,7 +301,10 @@ class CssModulesPlugin {
|
|||
.tap(PLUGIN_NAME, generatorOptions => {
|
||||
validateGeneratorOptions[type](generatorOptions);
|
||||
|
||||
return new CssGenerator(generatorOptions);
|
||||
return new CssGenerator(
|
||||
generatorOptions,
|
||||
compilation.moduleGraph
|
||||
);
|
||||
});
|
||||
normalModuleFactory.hooks.createModuleClass
|
||||
.for(type)
|
||||
|
|
|
|||
|
|
@ -361,6 +361,9 @@ class CssParser extends Parser {
|
|||
|
||||
const isModules = mode === "global" || mode === "local";
|
||||
|
||||
/** @type {BuildMeta} */
|
||||
(module.buildMeta).isCSSModule = isModules;
|
||||
|
||||
const locConverter = new LocConverter(source);
|
||||
|
||||
/** @type {number} */
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
const asyncLib = require("neo-async");
|
||||
const ChunkGraph = require("../ChunkGraph");
|
||||
const ModuleGraph = require("../ModuleGraph");
|
||||
const { JS_TYPE } = require("../ModuleSourceTypesConstants");
|
||||
const { STAGE_DEFAULT } = require("../OptimizationStages");
|
||||
const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
|
||||
const { compareModulesByIdentifier } = require("../util/comparators");
|
||||
|
|
@ -452,7 +453,7 @@ class ModuleConcatenationPlugin {
|
|||
chunkGraph.disconnectChunkAndModule(chunk, m);
|
||||
} else {
|
||||
const newSourceTypes = new Set(sourceTypes);
|
||||
newSourceTypes.delete("javascript");
|
||||
newSourceTypes.delete(JS_TYPE);
|
||||
chunkGraph.setChunkModuleSourceTypes(
|
||||
chunk,
|
||||
m,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ const vm = require("vm");
|
|||
const rimraf = require("rimraf");
|
||||
const checkArrayExpectation = require("./checkArrayExpectation");
|
||||
const createLazyTestEnv = require("./helpers/createLazyTestEnv");
|
||||
const FakeDocument = require("./helpers/FakeDocument");
|
||||
|
||||
const casesPath = path.join(__dirname, "hotCases");
|
||||
let categories = fs
|
||||
|
|
@ -108,8 +109,7 @@ const describeCases = config => {
|
|||
// ignored
|
||||
}
|
||||
|
||||
compiler = webpack(options);
|
||||
compiler.run((err, stats) => {
|
||||
const onCompiled = (err, stats) => {
|
||||
if (err) return done(err);
|
||||
const jsonStats = stats.toJson({
|
||||
errorDetails: true
|
||||
|
|
@ -179,9 +179,8 @@ const describeCases = config => {
|
|||
},
|
||||
document: {
|
||||
createElement(type) {
|
||||
return {
|
||||
const ele = {
|
||||
_type: type,
|
||||
sheet: {},
|
||||
getAttribute(name) {
|
||||
return this[name];
|
||||
},
|
||||
|
|
@ -199,6 +198,11 @@ const describeCases = config => {
|
|||
}
|
||||
}
|
||||
};
|
||||
ele.sheet =
|
||||
type === "link"
|
||||
? new FakeDocument.FakeSheet(ele, outputDirectory)
|
||||
: {};
|
||||
return ele;
|
||||
},
|
||||
head: {
|
||||
appendChild(element) {
|
||||
|
|
@ -353,8 +357,15 @@ const describeCases = config => {
|
|||
let promise = Promise.resolve();
|
||||
const info = stats.toJson({ all: false, entrypoints: true });
|
||||
if (config.target === "web") {
|
||||
for (const file of info.entrypoints.main.assets)
|
||||
_require(`./${file.name}`);
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const assets = info.entrypoints.main.assets;
|
||||
const result = _require(
|
||||
|
|
@ -375,7 +386,9 @@ const describeCases = config => {
|
|||
done(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
compiler = webpack(options);
|
||||
compiler.run(onCompiled);
|
||||
}, 20000);
|
||||
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
it("should compile and load style on demand", (done) => {
|
||||
import("./style.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
const style = getComputedStyle(document.body);
|
||||
expect(style.getPropertyValue("background")).toBe(" red");
|
||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import * as style from "./style.css";
|
||||
|
||||
it("should compile and load style on demand", done => {
|
||||
expect(style).toEqual(nsObj({}));
|
||||
expect(style).toEqual({});
|
||||
import("./style2.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import * as style from "./style.css";
|
||||
|
||||
it("should compile and load style on demand", done => {
|
||||
expect(style).toEqual(nsObj({}));
|
||||
expect(style).toEqual({});
|
||||
import("./style2.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
const style = getComputedStyle(document.body);
|
||||
expect(style.getPropertyValue("background")).toBe(" red");
|
||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as style from "./style.css";
|
||||
|
||||
it("should compile and load initial style", () => {
|
||||
expect(style).toEqual(nsObj({}));
|
||||
expect(style).toEqual({});
|
||||
const computedStyle = getComputedStyle(document.body);
|
||||
expect(computedStyle.getPropertyValue("background")).toBe(" red");
|
||||
expect(computedStyle.getPropertyValue("margin")).toBe(" 10px");
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import * as style from "./style.css";
|
||||
|
||||
it("should compile and load style on demand", done => {
|
||||
expect(style).toEqual(nsObj({}));
|
||||
expect(style).toEqual({});
|
||||
import("./style2.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
const style = getComputedStyle(document.body);
|
||||
expect(style.getPropertyValue("background")).toBe(" red");
|
||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import * as style from "./style.css";
|
||||
|
||||
it("should compile and load style on demand", done => {
|
||||
expect(style).toEqual(nsObj({}));
|
||||
expect(style).toEqual({});
|
||||
import("./style2.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
const style = getComputedStyle(document.body);
|
||||
expect(style.getPropertyValue("background")).toBe(" red");
|
||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ it("should work with js", done => {
|
|||
});
|
||||
|
||||
it("should work with css", done => {
|
||||
expect(style).toEqual(nsObj({}));
|
||||
expect(style).toEqual({});
|
||||
|
||||
const computedStyle = getComputedStyle(document.body);
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ it("should work with css", done => {
|
|||
expect(computedStyle.getPropertyValue("color")).toBe(" yellow");
|
||||
|
||||
import("./async.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
|
||||
const style = getComputedStyle(document.body);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
it("should import an external css", done => {
|
||||
import("../external/style.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
done();
|
||||
}, done);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
it("should import an external css", done => {
|
||||
import("./style.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
const style = getComputedStyle(document.body);
|
||||
expect(style.getPropertyValue("color")).toBe(" green");
|
||||
expect(style.getPropertyValue("background")).toBe(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as style from "./style.css";
|
||||
|
||||
it("should compile and load style on demand", () => {
|
||||
expect(style).toEqual(nsObj({}));
|
||||
expect(style).toEqual({});
|
||||
const computedStyle = getComputedStyle(document.body);
|
||||
expect(computedStyle.getPropertyValue("background")).toBe(" red");
|
||||
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";
|
||||
|
||||
it("should compile and load style on demand", done => {
|
||||
expect(style).toEqual(nsObj({}));
|
||||
expect(style).toEqual({});
|
||||
import("./style2.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
const style = getComputedStyle(document.body);
|
||||
expect(style.getPropertyValue("background")).toBe(" red");
|
||||
expect(style.getPropertyValue("margin")).toBe(" 10px");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import * as styles1 from "./style.less";
|
|||
import * as styles2 from "./style.modules.less";
|
||||
|
||||
it("should prefer relative", () => {
|
||||
expect(styles1).toEqual(nsObj({}));
|
||||
expect(styles1).toEqual({});
|
||||
expect(styles2).toEqual(nsObj({
|
||||
"style-module": "_style_modules_less-style-module",
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import * as styles1 from "./style.css";
|
|||
import * as styles2 from "./style.modules.css";
|
||||
|
||||
it("should prefer relative", () => {
|
||||
expect(styles1).toEqual(nsObj({}));
|
||||
expect(styles1).toEqual({});
|
||||
expect(styles2).toEqual(nsObj({
|
||||
"style-module": "_style_modules_css-style-module",
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import * as pureStyle from "./style.css";
|
|||
import * as styles from "./style.modules.css";
|
||||
|
||||
it("should work", done => {
|
||||
expect(pureStyle).toEqual(nsObj({}));
|
||||
expect(pureStyle).toEqual({});
|
||||
const style = getComputedStyle(document.body);
|
||||
expect(style.getPropertyValue("background")).toBe(" red");
|
||||
expect(styles.foo).toBe('_style_modules_css-foo');
|
||||
|
||||
import(/* webpackPrefetch: true */ "./style2.css").then(x => {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
const style = getComputedStyle(document.body);
|
||||
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);
|
||||
import("./index.css").then(x => {
|
||||
try {
|
||||
expect(x).toEqual(nsObj({}));
|
||||
expect(x).toEqual({});
|
||||
const style1 = getComputedStyle(h1);
|
||||
expect(style1).toMatchSnapshot();
|
||||
const style2 = getComputedStyle(h2);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ function getPropertyValue(property) {
|
|||
return this[property];
|
||||
}
|
||||
|
||||
module.exports = class FakeDocument {
|
||||
class FakeDocument {
|
||||
constructor(basePath) {
|
||||
this.head = this.createElement("head");
|
||||
this.body = this.createElement("body");
|
||||
|
|
@ -54,7 +54,7 @@ module.exports = class FakeDocument {
|
|||
}
|
||||
return style;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class FakeElement {
|
||||
constructor(document, type, basePath) {
|
||||
|
|
@ -252,3 +252,8 @@ class FakeSheet {
|
|||
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;
|
||||
sideEffectFree?: boolean;
|
||||
exportsFinalName?: Record<string, string>;
|
||||
isCSSModule?: boolean;
|
||||
}
|
||||
declare interface KnownCreateStatsOptionsContext {
|
||||
forToString?: boolean;
|
||||
|
|
|
|||
Loading…
Reference in New Issue