add test case

This commit is contained in:
Tobias Koppers 2021-12-01 09:50:13 +01:00
parent 8ae9507196
commit 110e8044dc
14 changed files with 163 additions and 20 deletions

View File

@ -59,10 +59,7 @@ class CssGenerator extends Generator {
template.apply(dependency, source, templateContext);
}
console.log(source);
const r = InitFragment.addToSource(source, initFragments, generateContext);
console.log(r);
return r;
return InitFragment.addToSource(source, initFragments, generateContext);
}
/**

View File

@ -136,9 +136,10 @@ class CssLoadingRuntimeModule extends RuntimeModule {
`tokens.forEach(${runtimeTemplate.basicFunction("token", [
`${
RuntimeGlobals.moduleFactories
}[token.slice(1)] = ${runtimeTemplate.basicFunction("module", [
"module.exports = {};"
])};`
}[token.slice(1)] = ${runtimeTemplate.basicFunction(
"module, exports",
[`${RuntimeGlobals.makeNamespaceObject}(exports);`]
)};`
])});`,
"installedChunks[chunkId] = 0;"
])}`,

View File

@ -151,6 +151,7 @@ class CssModulesPlugin {
set.add(RuntimeGlobals.getChunkCssFilename);
set.add(RuntimeGlobals.hasOwnProperty);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
set.add(RuntimeGlobals.makeNamespaceObject);
compilation.addRuntimeModule(chunk, new CssLoadingRuntimeModule(set));
};
@ -191,7 +192,7 @@ class CssModulesPlugin {
source.add(
`head{--webpack-${escapeCssIdentifierPart(chunk.id)}:${Array.from(
modules,
m => `_${escapeCssIdentifierPart(m.id)}`
m => `_${escapeCssIdentifierPart(chunkGraph.getModuleId(m))}`
).join(" ")};}`
);
return source;

View File

@ -59,9 +59,8 @@ class CssParser extends Parser {
});
module.buildInfo.strict = true;
module.buildMeta.exportsType = "default";
module.buildMeta.defaultObject = false;
module.addDependency(new StaticExportsDependency(["default"], true));
module.buildMeta.exportsType = "namespace";
module.addDependency(new StaticExportsDependency([], true));
return state;
}
}

View File

@ -309,13 +309,15 @@ const describeCases = config => {
const bundlePath = testConfig.findBundle(i, optionsArr[i]);
if (bundlePath) {
filesCount++;
const document = new FakeDocument();
const document = new FakeDocument(outputDirectory);
const globalContext = {
console: console,
expect: expect,
setTimeout: setTimeout,
clearTimeout: clearTimeout,
document,
getComputedStyle:
document.getComputedStyle.bind(document),
location: {
href: "https://test.cases/path/index.html",
origin: "https://test.cases",

View File

@ -497,7 +497,7 @@ describe("Validation", () => {
expect(msg).toMatchInlineSnapshot(`
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.output has an unknown property 'ecmaVersion'. These properties are valid:
object { assetModuleFilename?, asyncChunks?, auxiliaryComment?, charset?, chunkFilename?, chunkFormat?, chunkLoadTimeout?, chunkLoading?, chunkLoadingGlobal?, clean?, compareBeforeEmit?, crossOriginLoading?, devtoolFallbackModuleFilenameTemplate?, devtoolModuleFilenameTemplate?, devtoolNamespace?, enabledChunkLoadingTypes?, enabledLibraryTypes?, enabledWasmLoadingTypes?, environment?, filename?, globalObject?, hashDigest?, hashDigestLength?, hashFunction?, hashSalt?, hotUpdateChunkFilename?, hotUpdateGlobal?, hotUpdateMainFilename?, iife?, importFunctionName?, importMetaName?, library?, libraryExport?, libraryTarget?, module?, path?, pathinfo?, publicPath?, scriptType?, sourceMapFilename?, sourcePrefix?, strictModuleErrorHandling?, strictModuleExceptionHandling?, trustedTypes?, umdNamedDefine?, uniqueName?, wasmLoading?, webassemblyModuleFilename?, workerChunkLoading?, workerWasmLoading? }
object { assetModuleFilename?, asyncChunks?, auxiliaryComment?, charset?, chunkFilename?, chunkFormat?, chunkLoadTimeout?, chunkLoading?, chunkLoadingGlobal?, clean?, compareBeforeEmit?, crossOriginLoading?, cssFilename?, devtoolFallbackModuleFilenameTemplate?, devtoolModuleFilenameTemplate?, devtoolNamespace?, enabledChunkLoadingTypes?, enabledLibraryTypes?, enabledWasmLoadingTypes?, environment?, filename?, globalObject?, hashDigest?, hashDigestLength?, hashFunction?, hashSalt?, hotUpdateChunkFilename?, hotUpdateGlobal?, hotUpdateMainFilename?, iife?, importFunctionName?, importMetaName?, library?, libraryExport?, libraryTarget?, module?, path?, pathinfo?, publicPath?, scriptType?, sourceMapFilename?, sourcePrefix?, strictModuleErrorHandling?, strictModuleExceptionHandling?, trustedTypes?, umdNamedDefine?, uniqueName?, wasmLoading?, webassemblyModuleFilename?, workerChunkLoading?, workerWasmLoading? }
-> Options affecting the output of the compilation. \`output\` options tell webpack how to write the compiled files to disk.
Did you mean output.environment (output.ecmaVersion was a temporary configuration option during webpack 5 beta)?"
`)

View File

@ -594,6 +594,19 @@ Object {
"multiple": false,
"simpleType": "boolean",
},
"experiments-css": Object {
"configs": Array [
Object {
"description": "Enable css support.",
"multiple": false,
"path": "experiments.css",
"type": "boolean",
},
],
"description": "Enable css support.",
"multiple": false,
"simpleType": "boolean",
},
"experiments-future-defaults": Object {
"configs": Array [
Object {
@ -5175,6 +5188,19 @@ Object {
"multiple": false,
"simpleType": "string",
},
"output-css-filename": Object {
"configs": Array [
Object {
"description": "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.",
"multiple": false,
"path": "output.cssFilename",
"type": "string",
},
],
"description": "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.",
"multiple": false,
"simpleType": "string",
},
"output-devtool-fallback-module-filename-template": Object {
"configs": Array [
Object {

View File

@ -1,3 +0,0 @@
import "./style.css";
it("should compile", () => {});

View File

@ -0,0 +1,12 @@
import * as style from "./style.css";
it("should compile and load style on demand", done => {
expect(style).toEqual(nsObj({}));
import("./style2.css").then(x => {
expect(x).toEqual(nsObj({}));
const style = getComputedStyle(document.body);
expect(style.getPropertyValue("background")).toBe(" red");
expect(style.getPropertyValue("color")).toBe(" green");
done();
}, done);
});

View File

@ -0,0 +1,3 @@
body {
color: green;
}

View File

@ -0,0 +1,8 @@
module.exports = {
moduleScope(scope) {
const link = scope.window.document.createElement("link");
link.rel = "stylesheet";
link.href = "179.bundle0.css";
scope.window.document.head.appendChild(link);
}
};

View File

@ -0,0 +1,7 @@
/** @type {import("../../../../").Configuration} */
module.exports = {
target: "web",
experiments: {
css: true
}
};

View File

@ -1,12 +1,24 @@
const fs = require("fs");
const path = require("path");
const getPropertyValue = function (property) {
return this[property];
};
module.exports = class FakeDocument {
constructor() {
constructor(basePath) {
this.head = this.createElement("head");
this.body = this.createElement("body");
this.baseURI = "https://test.cases/path/index.html";
this._elementsByTagName = new Map([["head", [this.head]]]);
this._elementsByTagName = new Map([
["head", [this.head]],
["body", [this.body]]
]);
this._basePath = basePath;
}
createElement(type) {
return new FakeElement(this, type);
return new FakeElement(this, type, this._basePath);
}
_onElementAttached(element) {
@ -29,10 +41,23 @@ module.exports = class FakeDocument {
getElementsByTagName(name) {
return this._elementsByTagName.get(name) || [];
}
getComputedStyle(element) {
const style = { getPropertyValue };
const links = this.getElementsByTagName("link");
for (const link of links) {
for (const rule of link.sheet.cssRules) {
if (rule.selectorText === element._type) {
Object.assign(style, rule.style);
}
}
}
return style;
}
};
class FakeElement {
constructor(document, type) {
constructor(document, type, basePath) {
this._document = document;
this._type = type;
this._children = [];
@ -40,12 +65,18 @@ class FakeElement {
this._src = undefined;
this._href = undefined;
this.parentNode = undefined;
this.sheet = type === "link" ? new FakeSheet(this, basePath) : undefined;
}
appendChild(node) {
this._document._onElementAttached(node);
this._children.push(node);
node.parentNode = this;
if (node._type === "link") {
setTimeout(() => {
if (node.onload) node.onload({ type: "load", target: node });
}, 100);
}
}
removeChild(node) {
@ -61,6 +92,10 @@ class FakeElement {
this._attributes[name] = value;
}
removeAttribute(name) {
delete this._attributes[name];
}
getAttribute(name) {
return this._attributes[name];
}
@ -101,3 +136,58 @@ class FakeElement {
return this._href;
}
}
class FakeSheet {
constructor(element, basePath) {
this._element = element;
this._basePath = basePath;
}
get cssRules() {
const walkCssTokens = require("../../lib/css/walkCssTokens");
const rules = [];
let currentRule = { getPropertyValue };
let selector = undefined;
let last = 0;
const processDeclaration = str => {
const colon = str.indexOf(":");
if (colon > 0) {
const property = str.slice(0, colon).trim();
const value = str.slice(colon + 1);
currentRule[property] = value;
}
};
walkCssTokens(
fs.readFileSync(
path.resolve(
this._basePath,
this._element.href.replace(/^https:\/\/test\.cases\/path\//, "")
),
"utf-8"
),
{
leftCurlyBracket(source, start, end) {
if (selector === undefined) {
selector = source.slice(last, start).trim();
last = end;
}
return end;
},
rightCurlyBracket(source, start, end) {
processDeclaration(source.slice(last, start));
last = end;
rules.push({ selectorText: selector, style: currentRule });
selector = undefined;
currentRule = { getPropertyValue };
return end;
},
semicolon(source, start, end) {
processDeclaration(source.slice(last, start));
last = end;
return end;
}
}
);
return rules;
}
}