(https://github.com/ScriptedAlchemy)"
9 | ],
10 | "homepage": "http://github.com/faceyspacey/extract-css-chunks-webpack-plugin",
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/faceyspacey/extract-css-chunks-webpack-plugin.git"
14 | },
15 | "config": {
16 | "commitizen": {
17 | "path": "./node_modules/cz-conventional-changelog"
18 | }
19 | },
20 | "keywords": [
21 | "css",
22 | "chunks",
23 | "code splitting",
24 | "mini-css",
25 | "hot",
26 | "hmr",
27 | "universal",
28 | "webpack",
29 | "webpack 4",
30 | "css-hot-loader",
31 | "extract-css-chunks-webpack-plugin"
32 | ],
33 | "main": "dist/cjs.js",
34 | "types": "index.d.ts",
35 | "engines": {
36 | "node": ">= 6.9.0"
37 | },
38 | "scripts": {
39 | "commit": "git-cz",
40 | "start": "npm run build -- -w",
41 | "prebuild": "npm run clean",
42 | "build": "cross-env NODE_ENV=production babel src -d dist --ignore \"src/**/*.test.js\" --copy-files",
43 | "postbuild": "es-check es5 dist/hmr/hotModuleReplacement.js",
44 | "clean": "del-cli dist",
45 | "commitlint": "commitlint --from=master",
46 | "lint:prettier": "prettier \"{**/*,*}.{js,json,md,yml,css}\" --list-different",
47 | "lint:js": "eslint --cache src test",
48 | "lint": "npm-run-all -l -p \"lint:js\" \"lint:prettier\"",
49 | "prepare": "npm run build",
50 | "release": "standard-version",
51 | "security": "npm audit",
52 | "test:only": "cross-env NODE_ENV=test jest --updateSnapshot",
53 | "test:watch": "cross-env NODE_ENV=test jest --watch",
54 | "test:coverage": "cross-env NODE_ENV=test jest --collectCoverageFrom=\"src/**/*.js\" --coverage",
55 | "test:manual": "npm run build && webpack-dev-server test/manual/src/index.js --open --config test/manual/webpack.config.js",
56 | "pretest": "npm run lint",
57 | "test": "cross-env NODE_ENV=test npm run test:coverage",
58 | "defaults": "webpack-defaults",
59 | "semantic-release": "npx semantic-release",
60 | "travis": "npm run ci:coverage"
61 | },
62 | "files": [
63 | "dist",
64 | "index.d.ts"
65 | ],
66 | "peerDependencies": {
67 | "webpack": "^4.4.0 || ^5.0.0"
68 | },
69 | "dependencies": {
70 | "loader-utils": "^2.0.4",
71 | "normalize-url": "1.9.1",
72 | "schema-utils": "^1.0.0",
73 | "webpack-sources": "^1.1.0"
74 | },
75 | "devDependencies": {
76 | "@babel/cli": "7.8.4",
77 | "@babel/core": "7.9.0",
78 | "@babel/preset-env": "7.9.5",
79 | "@commitlint/cli": "8.3.5",
80 | "@commitlint/config-conventional": "8.3.4",
81 | "@webpack-contrib/defaults": "6.3.0",
82 | "@webpack-contrib/eslint-config-webpack": "3.0.0",
83 | "babel-eslint": "10.1.0",
84 | "babel-jest": "25.5.1",
85 | "commitizen": "4.0.4",
86 | "commitlint-azure-pipelines-cli": "1.0.3",
87 | "cross-env": "7.0.2",
88 | "css-loader": "3.5.2",
89 | "cz-conventional-changelog": "3.1.0",
90 | "del": "5.1.0",
91 | "del-cli": "3.0.0",
92 | "es-check": "5.1.0",
93 | "eslint": "6.8.0",
94 | "eslint-config-prettier": "6.10.1",
95 | "eslint-plugin-import": "2.20.2",
96 | "eslint-plugin-prettier": "3.1.2",
97 | "file-loader": "6.0.0",
98 | "husky": "4.2.3",
99 | "jest": "25.5.4",
100 | "jest-dev-server": "4.4.0",
101 | "jest-junit": "10.0.0",
102 | "jest-puppeteer": "4.4.0",
103 | "lint-staged": "10.0.8",
104 | "memfs": "3.1.2",
105 | "npm-run-all": "4.1.5",
106 | "prerender-loader": "1.3.0",
107 | "prettier": "1.19.1",
108 | "puppeteer": "2.1.1",
109 | "serve": "11.3.0",
110 | "standard-version": "8.0.1",
111 | "webpack": "4.43.0",
112 | "webpack-cli": "3.3.11",
113 | "webpack-dev-server": "3.10.3"
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | ":combinePatchMinorReleases",
4 | ":ignoreUnstable",
5 | ":prImmediately",
6 | ":semanticPrefixFixDepsChoreOthers",
7 | ":updateNotScheduled",
8 | ":automergeDisabled",
9 | ":ignoreModulesAndTests",
10 | ":maintainLockFilesDisabled",
11 | ":autodetectPinVersions",
12 | ":prHourlyLimit4",
13 | ":prConcurrentLimit20",
14 | "group:monorepos",
15 | "group:recommended",
16 | "helpers:disableTypesNodeMajor",
17 | ":pinAllExceptPeerDependencies",
18 | ":pinOnlyDevDependencies"
19 | ],
20 | "packageRules": [
21 | {
22 | "packageNames": ["normalize-url"],
23 | "allowedVersions": "1.9.1"
24 | },
25 | {
26 | "packageNames": ["schema-utils"],
27 | "allowedVersions": "^1"
28 | },
29 | { "updateTypes": ["minor", "patch", "pin", "digest"] }
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/src/CssDependency.js:
--------------------------------------------------------------------------------
1 | import webpack from 'webpack';
2 |
3 | export default class CssDependency extends webpack.Dependency {
4 | constructor(
5 | { identifier, content, media, sourceMap },
6 | context,
7 | identifierIndex
8 | ) {
9 | super();
10 |
11 | this.identifier = identifier;
12 | this.identifierIndex = identifierIndex;
13 | this.content = content;
14 | this.media = media;
15 | this.sourceMap = sourceMap;
16 | this.context = context;
17 | }
18 |
19 | getResourceIdentifier() {
20 | return `css-module-${this.identifier}-${this.identifierIndex}`;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/cjs.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./index').default;
2 |
--------------------------------------------------------------------------------
/src/hmr/hotModuleReplacement.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 | /*
3 | eslint-disable
4 | no-console,
5 | func-names
6 | */
7 |
8 | const normalizeUrl = require('normalize-url');
9 |
10 | const srcByModuleId = Object.create(null);
11 |
12 | const noDocument = typeof document === 'undefined';
13 |
14 | const { forEach } = Array.prototype;
15 |
16 | function debounce(fn, time) {
17 | let timeout = 0;
18 |
19 | return function() {
20 | const self = this;
21 | // eslint-disable-next-line prefer-rest-params
22 | const args = arguments;
23 |
24 | const functionCall = function functionCall() {
25 | return fn.apply(self, args);
26 | };
27 |
28 | clearTimeout(timeout);
29 | timeout = setTimeout(functionCall, time);
30 | };
31 | }
32 |
33 | function noop() {}
34 |
35 | function getCurrentScriptUrl(moduleId) {
36 | let src = srcByModuleId[moduleId];
37 |
38 | if (!src) {
39 | if (document.currentScript) {
40 | ({ src } = document.currentScript);
41 | } else {
42 | const scripts = document.getElementsByTagName('script');
43 | const lastScriptTag = scripts[scripts.length - 1];
44 |
45 | if (lastScriptTag) {
46 | ({ src } = lastScriptTag);
47 | }
48 | }
49 |
50 | srcByModuleId[moduleId] = src;
51 | }
52 |
53 | return function(fileMap) {
54 | if (!src) {
55 | return null;
56 | }
57 |
58 | const splitResult = src.split(/([^\\/]+)\.js$/);
59 | const filename = splitResult && splitResult[1];
60 |
61 | if (!filename) {
62 | return [src.replace('.js', '.css')];
63 | }
64 |
65 | if (!fileMap) {
66 | return [src.replace('.js', '.css')];
67 | }
68 |
69 | return fileMap.split(',').map((mapRule) => {
70 | const reg = new RegExp(`${filename}\\.js$`, 'g');
71 |
72 | return normalizeUrl(
73 | src.replace(reg, `${mapRule.replace(/{fileName}/g, filename)}.css`),
74 | { stripWWW: false }
75 | );
76 | });
77 | };
78 | }
79 |
80 | function updateCss(el, url) {
81 | if (!url) {
82 | if (!el.href) {
83 | return;
84 | }
85 |
86 | // eslint-disable-next-line
87 | url = el.href.split('?')[0];
88 | }
89 |
90 | if (!isUrlRequest(url)) {
91 | return;
92 | }
93 |
94 | if (el.isLoaded === false) {
95 | // We seem to be about to replace a css link that hasn't loaded yet.
96 | // We're probably changing the same file more than once.
97 | return;
98 | }
99 |
100 | if (!url || !(url.indexOf('.css') > -1)) {
101 | return;
102 | }
103 |
104 | // eslint-disable-next-line no-param-reassign
105 | el.visited = true;
106 |
107 | const newEl = el.cloneNode();
108 |
109 | newEl.isLoaded = false;
110 |
111 | newEl.addEventListener('load', () => {
112 | newEl.isLoaded = true;
113 | el.parentNode.removeChild(el);
114 | });
115 |
116 | newEl.addEventListener('error', () => {
117 | newEl.isLoaded = true;
118 | el.parentNode.removeChild(el);
119 | });
120 |
121 | newEl.href = `${url}?${Date.now()}`;
122 |
123 | if (el.nextSibling) {
124 | el.parentNode.insertBefore(newEl, el.nextSibling);
125 | } else {
126 | el.parentNode.appendChild(newEl);
127 | }
128 | }
129 |
130 | function getReloadUrl(href, src) {
131 | let ret;
132 |
133 | // eslint-disable-next-line no-param-reassign
134 | href = normalizeUrl(href, { stripWWW: false });
135 |
136 | // eslint-disable-next-line array-callback-return
137 | src.some((url) => {
138 | if (href.indexOf(src) > -1) {
139 | ret = url;
140 | }
141 | });
142 |
143 | return ret;
144 | }
145 |
146 | function reloadStyle(src) {
147 | const elements = document.querySelectorAll('link');
148 | let loaded = false;
149 |
150 | forEach.call(elements, (el) => {
151 | if (!el.href) {
152 | return;
153 | }
154 |
155 | const url = getReloadUrl(el.href, src);
156 |
157 | if (!isUrlRequest(url)) {
158 | return;
159 | }
160 |
161 | if (el.visited === true) {
162 | return;
163 | }
164 |
165 | if (url) {
166 | updateCss(el, url);
167 |
168 | loaded = true;
169 | }
170 | });
171 |
172 | return loaded;
173 | }
174 |
175 | function reloadAll() {
176 | const elements = document.querySelectorAll('link');
177 |
178 | forEach.call(elements, (el) => {
179 | if (el.visited === true) {
180 | return;
181 | }
182 |
183 | updateCss(el);
184 | });
185 | }
186 |
187 | function isUrlRequest(url) {
188 | // An URL is not an request if
189 |
190 | // It is not http or https
191 | if (!/^https?:/i.test(url)) {
192 | return false;
193 | }
194 |
195 | return true;
196 | }
197 |
198 | module.exports = function(moduleId, options) {
199 | if (noDocument) {
200 | console.log('no window.document found, will not HMR CSS');
201 |
202 | return noop;
203 | }
204 |
205 | const getScriptSrc = getCurrentScriptUrl(moduleId);
206 |
207 | function update() {
208 | const src = getScriptSrc(options.filename);
209 | const reloaded = reloadStyle(src);
210 |
211 | if (options.locals) {
212 | console.log('[HMR] Detected local css modules. Reload all css');
213 |
214 | reloadAll();
215 |
216 | return;
217 | }
218 |
219 | if (reloaded && !options.reloadAll) {
220 | console.log('[HMR] css reload %s', src.join(' '));
221 | } else {
222 | console.log('[HMR] Reload all css');
223 |
224 | reloadAll();
225 | }
226 | }
227 |
228 | return debounce(update, 50);
229 | };
230 |
--------------------------------------------------------------------------------
/src/loader-options.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "object",
3 | "additionalProperties": true,
4 | "properties": {
5 | "publicPath": {
6 | "anyOf": [
7 | {
8 | "type": "string"
9 | },
10 | {
11 | "instanceof": "Function"
12 | }
13 | ]
14 | },
15 | "esModule": {
16 | "type": "boolean"
17 | },
18 | "hmr": {
19 | "type": "boolean"
20 | },
21 | "reloadAll": {
22 | "type": "boolean"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/loader.js:
--------------------------------------------------------------------------------
1 | import NativeModule from 'module';
2 |
3 | import path from 'path';
4 |
5 | import loaderUtils from 'loader-utils';
6 | import NodeTemplatePlugin from 'webpack/lib/node/NodeTemplatePlugin';
7 | import NodeTargetPlugin from 'webpack/lib/node/NodeTargetPlugin';
8 | import LibraryTemplatePlugin from 'webpack/lib/LibraryTemplatePlugin';
9 | import SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin';
10 | import LimitChunkCountPlugin from 'webpack/lib/optimize/LimitChunkCountPlugin';
11 | import validateOptions from 'schema-utils';
12 |
13 | import CssDependency from './CssDependency';
14 |
15 | import schema from './loader-options.json';
16 |
17 | const pluginName = 'extract-css-chunks-webpack-plugin';
18 |
19 | function hotLoader(content, context) {
20 | const accept = context.locals
21 | ? ''
22 | : 'module.hot.accept(undefined, cssReload);';
23 |
24 | return `${content}
25 | if(module.hot) {
26 | // ${Date.now()}
27 | var cssReload = require(${loaderUtils.stringifyRequest(
28 | context.context,
29 | path.join(__dirname, 'hmr/hotModuleReplacement.js')
30 | )})(module.id, ${JSON.stringify({
31 | ...context.options,
32 | locals: !!context.locals,
33 | })});
34 | module.hot.dispose(cssReload);
35 | ${accept}
36 | }
37 | `;
38 | }
39 |
40 | function evalModuleCode(loaderContext, code, filename) {
41 | const module = new NativeModule(filename, loaderContext);
42 |
43 | module.paths = NativeModule._nodeModulePaths(loaderContext.context); // eslint-disable-line no-underscore-dangle
44 | module.filename = filename;
45 | module._compile(code, filename); // eslint-disable-line no-underscore-dangle
46 |
47 | return module.exports;
48 | }
49 |
50 | function findModuleById(modules, id) {
51 | for (const module of modules) {
52 | if (module.id === id) {
53 | return module;
54 | }
55 | }
56 |
57 | return null;
58 | }
59 |
60 | export function pitch(request) {
61 | const options = loaderUtils.getOptions(this) || {};
62 |
63 | validateOptions(schema, options, 'Mini CSS Extract Plugin Loader');
64 |
65 | const loaders = this.loaders.slice(this.loaderIndex + 1);
66 |
67 | this.addDependency(this.resourcePath);
68 |
69 | const childFilename = '*';
70 | const publicPath =
71 | typeof options.publicPath === 'string'
72 | ? options.publicPath === '' || options.publicPath.endsWith('/')
73 | ? options.publicPath
74 | : `${options.publicPath}/`
75 | : typeof options.publicPath === 'function'
76 | ? options.publicPath(this.resourcePath, this.rootContext)
77 | : this._compilation.outputOptions.publicPath;
78 | const outputOptions = {
79 | filename: childFilename,
80 | publicPath,
81 | };
82 | const childCompiler = this._compilation.createChildCompiler(
83 | `${pluginName} ${request}`,
84 | outputOptions
85 | );
86 |
87 | new NodeTemplatePlugin(outputOptions).apply(childCompiler);
88 | new LibraryTemplatePlugin(null, 'commonjs2').apply(childCompiler);
89 | new NodeTargetPlugin().apply(childCompiler);
90 | new SingleEntryPlugin(this.context, `!!${request}`, pluginName).apply(
91 | childCompiler
92 | );
93 | new LimitChunkCountPlugin({ maxChunks: 1 }).apply(childCompiler);
94 |
95 | childCompiler.hooks.thisCompilation.tap(
96 | `${pluginName} loader`,
97 | (compilation) => {
98 | compilation.hooks.normalModuleLoader.tap(
99 | `${pluginName} loader`,
100 | (loaderContext, module) => {
101 | // eslint-disable-next-line no-param-reassign
102 | loaderContext.emitFile = this.emitFile;
103 |
104 | if (module.request === request) {
105 | // eslint-disable-next-line no-param-reassign
106 | module.loaders = loaders.map((loader) => {
107 | return {
108 | loader: loader.path,
109 | options: loader.options,
110 | ident: loader.ident,
111 | };
112 | });
113 | }
114 | }
115 | );
116 | }
117 | );
118 |
119 | let source;
120 |
121 | childCompiler.hooks.afterCompile.tap(pluginName, (compilation) => {
122 | source =
123 | compilation.assets[childFilename] &&
124 | compilation.assets[childFilename].source();
125 |
126 | // Remove all chunk assets
127 | compilation.chunks.forEach((chunk) => {
128 | chunk.files.forEach((file) => {
129 | delete compilation.assets[file]; // eslint-disable-line no-param-reassign
130 | });
131 | });
132 | });
133 |
134 | const callback = this.async();
135 |
136 | childCompiler.runAsChild((err, entries, compilation) => {
137 | const addDependencies = (dependencies) => {
138 | if (!Array.isArray(dependencies) && dependencies != null) {
139 | throw new Error(
140 | `Exported value was not extracted as an array: ${JSON.stringify(
141 | dependencies
142 | )}`
143 | );
144 | }
145 |
146 | const identifierCountMap = new Map();
147 |
148 | for (const dependency of dependencies) {
149 | const count = identifierCountMap.get(dependency.identifier) || 0;
150 |
151 | this._module.addDependency(
152 | new CssDependency(dependency, dependency.context, count)
153 | );
154 | identifierCountMap.set(dependency.identifier, count + 1);
155 | }
156 | };
157 |
158 | if (err) {
159 | return callback(err);
160 | }
161 |
162 | if (compilation.errors.length > 0) {
163 | return callback(compilation.errors[0]);
164 | }
165 |
166 | compilation.fileDependencies.forEach((dep) => {
167 | this.addDependency(dep);
168 | }, this);
169 |
170 | compilation.contextDependencies.forEach((dep) => {
171 | this.addContextDependency(dep);
172 | }, this);
173 |
174 | if (!source) {
175 | return callback(new Error("Didn't get a result from child compiler"));
176 | }
177 |
178 | let locals;
179 |
180 | try {
181 | let dependencies;
182 | let exports = evalModuleCode(this, source, request);
183 | // eslint-disable-next-line no-underscore-dangle
184 | exports = exports.__esModule ? exports.default : exports;
185 | locals = exports && exports.locals;
186 | if (!Array.isArray(exports)) {
187 | dependencies = [[null, exports]];
188 | } else {
189 | dependencies = exports.map(([id, content, media, sourceMap]) => {
190 | const module = findModuleById(compilation.modules, id);
191 |
192 | return {
193 | identifier: module.identifier(),
194 | context: module.context,
195 | content,
196 | media,
197 | sourceMap,
198 | };
199 | });
200 | }
201 | addDependencies(dependencies);
202 | } catch (e) {
203 | return callback(e);
204 | }
205 |
206 | const esModule =
207 | typeof options.esModule !== 'undefined' ? options.esModule : false;
208 | const result = locals
209 | ? `\n${esModule ? 'export default' : 'module.exports ='} ${JSON.stringify(
210 | locals
211 | )};`
212 | : '';
213 |
214 | let resultSource = `// extracted by ${pluginName}`;
215 |
216 | resultSource += options.hmr
217 | ? hotLoader(result, { context: this.context, options, locals })
218 | : result;
219 |
220 | return callback(null, resultSource);
221 | });
222 | }
223 |
224 | export default function() {}
225 |
--------------------------------------------------------------------------------
/src/plugin-options.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "object",
3 | "additionalProperties": true,
4 | "properties": {
5 | "filename": {
6 | "type": "string"
7 | },
8 | "chunkFilename": {
9 | "type": "string"
10 | },
11 | "moduleFilename": {
12 | "instanceof": "Function"
13 | },
14 | "ignoreOrder": {
15 | "type": "boolean"
16 | },
17 | "insert": {
18 | "description": "Inserts `` at the given position (https://github.com/faceyspacey/extract-css-chunks-webpack-pluginn#insert).",
19 | "anyOf": [
20 | {
21 | "type": "string"
22 | },
23 | {
24 | "instanceof": "Function"
25 | }
26 | ]
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/HMR.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @jest-environment jsdom
3 | */
4 | /* eslint-env browser */
5 | /* eslint-disable no-console */
6 |
7 | import hotModuleReplacement from '../src/hmr/hotModuleReplacement';
8 |
9 | function getLoadEvent() {
10 | const event = document.createEvent('Event');
11 |
12 | event.initEvent('load', false, false);
13 |
14 | return event;
15 | }
16 |
17 | function getErrorEvent() {
18 | const event = document.createEvent('Event');
19 |
20 | event.initEvent('error', false, false);
21 |
22 | return event;
23 | }
24 |
25 | describe('HMR', () => {
26 | let consoleMock = null;
27 |
28 | beforeEach(() => {
29 | consoleMock = jest.spyOn(console, 'log').mockImplementation(() => () => {});
30 |
31 | jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000);
32 |
33 | document.head.innerHTML =
34 | '';
35 | document.body.innerHTML = '';
36 | });
37 |
38 | afterEach(() => {
39 | consoleMock.mockClear();
40 | });
41 |
42 | it('should works', (done) => {
43 | const update = hotModuleReplacement('./src/style.css', {});
44 |
45 | update();
46 |
47 | setTimeout(() => {
48 | expect(console.log.mock.calls[0][0]).toMatchSnapshot();
49 |
50 | const links = Array.prototype.slice.call(
51 | document.querySelectorAll('link')
52 | );
53 |
54 | expect(links[0].visited).toBe(true);
55 | expect(document.head.innerHTML).toMatchSnapshot();
56 |
57 | links[1].dispatchEvent(getLoadEvent());
58 |
59 | expect(links[1].isLoaded).toBe(true);
60 |
61 | done();
62 | }, 100);
63 | });
64 |
65 | it('should works with multiple updates', (done) => {
66 | const update = hotModuleReplacement('./src/style.css', {});
67 |
68 | update();
69 |
70 | setTimeout(() => {
71 | expect(console.log.mock.calls[0][0]).toMatchSnapshot();
72 |
73 | const links = Array.prototype.slice.call(
74 | document.querySelectorAll('link')
75 | );
76 |
77 | expect(links[0].visited).toBe(true);
78 | expect(document.head.innerHTML).toMatchSnapshot();
79 |
80 | links[1].dispatchEvent(getLoadEvent());
81 |
82 | expect(links[1].isLoaded).toBe(true);
83 |
84 | jest.spyOn(Date, 'now').mockImplementation(() => 1479427200001);
85 |
86 | const update2 = hotModuleReplacement('./src/style.css', {});
87 |
88 | update2();
89 |
90 | setTimeout(() => {
91 | const links2 = Array.prototype.slice.call(
92 | document.querySelectorAll('link')
93 | );
94 |
95 | expect(links2[0].visited).toBe(true);
96 | expect(links2[0].isLoaded).toBe(true);
97 | expect(document.head.innerHTML).toMatchSnapshot();
98 |
99 | links2[1].dispatchEvent(getLoadEvent());
100 |
101 | expect(links2[1].isLoaded).toBe(true);
102 |
103 | done();
104 | }, 100);
105 | }, 100);
106 | });
107 |
108 | it('should reloads with locals', (done) => {
109 | const update = hotModuleReplacement('./src/style.css', {
110 | locals: { foo: 'bar' },
111 | });
112 |
113 | update();
114 |
115 | setTimeout(() => {
116 | expect(console.log.mock.calls[0][0]).toMatchSnapshot();
117 |
118 | const links = Array.prototype.slice.call(
119 | document.querySelectorAll('link')
120 | );
121 |
122 | expect(links[0].visited).toBe(true);
123 | expect(document.head.innerHTML).toMatchSnapshot();
124 |
125 | links[1].dispatchEvent(getLoadEvent());
126 |
127 | expect(links[1].isLoaded).toBe(true);
128 |
129 | done();
130 | }, 100);
131 | });
132 |
133 | it('should reloads with reloadAll option', (done) => {
134 | const update = hotModuleReplacement('./src/style.css', {
135 | reloadAll: true,
136 | });
137 |
138 | update();
139 |
140 | setTimeout(() => {
141 | expect(console.log.mock.calls[0][0]).toMatchSnapshot();
142 |
143 | const links = Array.prototype.slice.call(
144 | document.querySelectorAll('link')
145 | );
146 |
147 | expect(links[0].visited).toBe(true);
148 | expect(document.head.innerHTML).toMatchSnapshot();
149 |
150 | links[1].dispatchEvent(getLoadEvent());
151 |
152 | expect(links[1].isLoaded).toBe(true);
153 |
154 | done();
155 | }, 100);
156 | });
157 |
158 | it('should reloads with non http/https link href', (done) => {
159 | document.head.innerHTML =
160 | '';
161 |
162 | const update = hotModuleReplacement('./src/style.css', {});
163 |
164 | update();
165 |
166 | setTimeout(() => {
167 | expect(console.log.mock.calls[0][0]).toMatchSnapshot();
168 |
169 | const links = Array.prototype.slice.call(
170 | document.querySelectorAll('link')
171 | );
172 |
173 | expect(links[0].visited).toBe(true);
174 | expect(document.head.innerHTML).toMatchSnapshot();
175 |
176 | links[1].dispatchEvent(getLoadEvent());
177 |
178 | expect(links[1].isLoaded).toBe(true);
179 | expect(links[2].visited).toBeUndefined();
180 |
181 | done();
182 | }, 100);
183 | });
184 |
185 | it('should reloads with # link href', (done) => {
186 | document.head.innerHTML =
187 | '';
188 |
189 | const update = hotModuleReplacement('./src/style.css', {});
190 |
191 | update();
192 |
193 | setTimeout(() => {
194 | expect(console.log.mock.calls[0][0]).toMatchSnapshot();
195 |
196 | const links = Array.prototype.slice.call(
197 | document.querySelectorAll('link')
198 | );
199 |
200 | expect(links[0].visited).toBe(true);
201 | expect(document.head.innerHTML).toMatchSnapshot();
202 |
203 | links[1].dispatchEvent(getLoadEvent());
204 |
205 | expect(links[1].isLoaded).toBe(true);
206 | expect(links[2].visited).toBeUndefined();
207 |
208 | done();
209 | }, 100);
210 | });
211 |
212 | it('should reloads with link without href', (done) => {
213 | document.head.innerHTML =
214 | '';
215 |
216 | const update = hotModuleReplacement('./src/style.css', {});
217 |
218 | update();
219 |
220 | setTimeout(() => {
221 | expect(console.log.mock.calls[0][0]).toMatchSnapshot();
222 |
223 | const links = Array.prototype.slice.call(
224 | document.querySelectorAll('link')
225 | );
226 |
227 | expect(links[0].visited).toBe(true);
228 | expect(document.head.innerHTML).toMatchSnapshot();
229 |
230 | links[1].dispatchEvent(getLoadEvent());
231 |
232 | expect(links[1].isLoaded).toBe(true);
233 | expect(links[2].visited).toBeUndefined();
234 |
235 | done();
236 | }, 100);
237 | });
238 |
239 | it('should reloads with absolute remove url', (done) => {
240 | document.head.innerHTML =
241 | '';
242 |
243 | const update = hotModuleReplacement('./src/style.css', {});
244 |
245 | update();
246 |
247 | setTimeout(() => {
248 | expect(console.log.mock.calls[0][0]).toMatchSnapshot();
249 |
250 | const links = Array.prototype.slice.call(
251 | document.querySelectorAll('link')
252 | );
253 |
254 | expect(links[0].visited).toBe(true);
255 | expect(document.head.innerHTML).toMatchSnapshot();
256 |
257 | links[1].dispatchEvent(getLoadEvent());
258 |
259 | expect(links[1].isLoaded).toBe(true);
260 | expect(links[2].visited).toBeUndefined();
261 |
262 | done();
263 | }, 100);
264 | });
265 |
266 | it('should handle error event', (done) => {
267 | const update = hotModuleReplacement('./src/style.css', {});
268 |
269 | update();
270 |
271 | setTimeout(() => {
272 | expect(console.log.mock.calls[0][0]).toMatchSnapshot();
273 |
274 | const links = Array.prototype.slice.call(
275 | document.querySelectorAll('link')
276 | );
277 |
278 | expect(links[0].visited).toBe(true);
279 | expect(document.head.innerHTML).toMatchSnapshot();
280 |
281 | links[1].dispatchEvent(getErrorEvent());
282 |
283 | expect(links[1].isLoaded).toBe(true);
284 |
285 | done();
286 | }, 100);
287 | });
288 | });
289 |
--------------------------------------------------------------------------------
/test/TestCases.test.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import path from 'path';
3 |
4 | import webpack from 'webpack';
5 |
6 | function compareDirectory(actual, expected) {
7 | const files = fs.readdirSync(expected);
8 |
9 | for (const file of files) {
10 | const absoluteFilePath = path.resolve(expected, file);
11 |
12 | const stats = fs.lstatSync(absoluteFilePath);
13 |
14 | if (stats.isDirectory()) {
15 | compareDirectory(
16 | path.resolve(actual, file),
17 | path.resolve(expected, file)
18 | );
19 | } else if (stats.isFile()) {
20 | const content = fs.readFileSync(path.resolve(expected, file), 'utf8');
21 | const actualContent = fs.readFileSync(path.resolve(actual, file), 'utf8');
22 |
23 | expect(actualContent).toEqual(content);
24 | }
25 | }
26 | }
27 |
28 | function compareWarning(actual, expectedFile) {
29 | if (!fs.existsSync(expectedFile)) {
30 | return;
31 | }
32 |
33 | // eslint-disable-next-line global-require, import/no-dynamic-require
34 | const expected = require(expectedFile);
35 |
36 | expect(actual.trim()).toBe(expected.trim());
37 | }
38 |
39 | describe('TestCases', () => {
40 | const casesDirectory = path.resolve(__dirname, 'cases');
41 | const outputDirectory = path.resolve(__dirname, 'js');
42 |
43 | for (const directory of fs.readdirSync(casesDirectory)) {
44 | if (!/^(\.|_)/.test(directory)) {
45 | // eslint-disable-next-line no-loop-func
46 | it(`${directory} should compile to the expected result`, (done) => {
47 | const directoryForCase = path.resolve(casesDirectory, directory);
48 | const outputDirectoryForCase = path.resolve(outputDirectory, directory);
49 | // eslint-disable-next-line import/no-dynamic-require, global-require
50 | const webpackConfig = require(path.resolve(
51 | directoryForCase,
52 | 'webpack.config.js'
53 | ));
54 |
55 | for (const config of [].concat(webpackConfig)) {
56 | Object.assign(
57 | config,
58 | {
59 | mode: 'none',
60 | context: directoryForCase,
61 | output: Object.assign(
62 | {
63 | path: outputDirectoryForCase,
64 | },
65 | config.output
66 | ),
67 | },
68 | config
69 | );
70 | }
71 |
72 | webpack(webpackConfig, (err, stats) => {
73 | if (err) {
74 | done(err);
75 | return;
76 | }
77 |
78 | done();
79 |
80 | // eslint-disable-next-line no-console
81 | console.log(
82 | stats.toString({
83 | context: path.resolve(__dirname, '..'),
84 | chunks: true,
85 | chunkModules: true,
86 | modules: false,
87 | })
88 | );
89 |
90 | if (stats.hasErrors()) {
91 | done(
92 | new Error(
93 | stats.toString({
94 | context: path.resolve(__dirname, '..'),
95 | errorDetails: true,
96 | })
97 | )
98 | );
99 |
100 | return;
101 | }
102 |
103 | const expectedDirectory = path.resolve(directoryForCase, 'expected');
104 | const expectedDirectoryByVersion = path.join(
105 | expectedDirectory,
106 | `webpack-${webpack.version[0]}`
107 | );
108 |
109 | if (fs.existsSync(expectedDirectoryByVersion)) {
110 | compareDirectory(
111 | outputDirectoryForCase,
112 | expectedDirectoryByVersion
113 | );
114 | } else {
115 | compareDirectory(outputDirectoryForCase, expectedDirectory);
116 | }
117 |
118 | const expectedWarning = path.resolve(directoryForCase, 'warnings.js');
119 | const actualWarning = stats.toString({
120 | all: false,
121 | warnings: true,
122 | });
123 | compareWarning(actualWarning, expectedWarning);
124 |
125 | done();
126 | });
127 | }, 10000);
128 | }
129 | }
130 | });
131 |
--------------------------------------------------------------------------------
/test/TestMemoryFS.test.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 |
3 | import { createFsFromVolume, Volume } from 'memfs';
4 | import webpack from 'webpack';
5 |
6 | const assetsNames = (json) => json.assets.map((asset) => asset.name);
7 |
8 | describe('TestMemoryFS', () => {
9 | it('should preserve asset even if not emitted', (done) => {
10 | const casesDirectory = path.resolve(__dirname, 'cases');
11 | const directoryForCase = path.resolve(casesDirectory, 'simple-publicpath');
12 | // eslint-disable-next-line import/no-dynamic-require, global-require
13 | const webpackConfig = require(path.resolve(
14 | directoryForCase,
15 | 'webpack.config.js'
16 | ));
17 | const compiler = webpack({
18 | ...webpackConfig,
19 | mode: 'development',
20 | context: directoryForCase,
21 | cache: false,
22 | });
23 | const outputFileSystem = createFsFromVolume(new Volume());
24 | // Todo remove when we drop webpack@4 support
25 | outputFileSystem.join = path.join.bind(path);
26 |
27 | compiler.outputFileSystem = outputFileSystem;
28 |
29 | compiler.run((err1, stats1) => {
30 | if (err1) {
31 | done(err1);
32 |
33 | return;
34 | }
35 |
36 | compiler.run((err2, stats2) => {
37 | if (err2) {
38 | done(err2);
39 |
40 | return;
41 | }
42 |
43 | expect(assetsNames(stats1.toJson())).toEqual(
44 | assetsNames(stats2.toJson())
45 | );
46 |
47 | done();
48 | });
49 | });
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/test/__snapshots__/HMR.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`HMR should handle error event 1`] = `"[HMR] css reload %s"`;
4 |
5 | exports[`HMR should handle error event 2`] = `""`;
6 |
7 | exports[`HMR should reloads with # link href 1`] = `"[HMR] css reload %s"`;
8 |
9 | exports[`HMR should reloads with # link href 2`] = `""`;
10 |
11 | exports[`HMR should reloads with absolute remove url 1`] = `"[HMR] css reload %s"`;
12 |
13 | exports[`HMR should reloads with absolute remove url 2`] = `""`;
14 |
15 | exports[`HMR should reloads with link without href 1`] = `"[HMR] css reload %s"`;
16 |
17 | exports[`HMR should reloads with link without href 2`] = `""`;
18 |
19 | exports[`HMR should reloads with locals 1`] = `"[HMR] Detected local css modules. Reload all css"`;
20 |
21 | exports[`HMR should reloads with locals 2`] = `""`;
22 |
23 | exports[`HMR should reloads with non http/https link href 1`] = `"[HMR] css reload %s"`;
24 |
25 | exports[`HMR should reloads with non http/https link href 2`] = `""`;
26 |
27 | exports[`HMR should reloads with reloadAll option 1`] = `"[HMR] Reload all css"`;
28 |
29 | exports[`HMR should reloads with reloadAll option 2`] = `""`;
30 |
31 | exports[`HMR should works 1`] = `"[HMR] css reload %s"`;
32 |
33 | exports[`HMR should works 2`] = `""`;
34 |
35 | exports[`HMR should works with multiple updates 1`] = `"[HMR] css reload %s"`;
36 |
37 | exports[`HMR should works with multiple updates 2`] = `""`;
38 |
39 | exports[`HMR should works with multiple updates 3`] = `""`;
40 |
--------------------------------------------------------------------------------
/test/__snapshots__/validate-loader-options.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`validate options should throw an error on the "esModule" option with "1" value 1`] = `
4 | "Mini CSS Extract Plugin Loader Invalid Options
5 |
6 | options.esModule should be boolean
7 | "
8 | `;
9 |
10 | exports[`validate options should throw an error on the "hmr" option with "1" value 1`] = `
11 | "Mini CSS Extract Plugin Loader Invalid Options
12 |
13 | options.hmr should be boolean
14 | "
15 | `;
16 |
17 | exports[`validate options should throw an error on the "publicPath" option with "true" value 1`] = `
18 | "Mini CSS Extract Plugin Loader Invalid Options
19 |
20 | options.publicPath should be string
21 | options.publicPath should pass \\"instanceof\\" keyword validation
22 | options.publicPath should match some schema in anyOf
23 | "
24 | `;
25 |
26 | exports[`validate options should throw an error on the "reloadAll" option with "1" value 1`] = `
27 | "Mini CSS Extract Plugin Loader Invalid Options
28 |
29 | options.reloadAll should be boolean
30 | "
31 | `;
32 |
--------------------------------------------------------------------------------
/test/__snapshots__/validate-plugin-options.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`validate options should throw an error on the "chunkFilename" option with "true" value 1`] = `
4 | "Mini CSS Extract Plugin Invalid Options
5 |
6 | options.chunkFilename should be string
7 | "
8 | `;
9 |
10 | exports[`validate options should throw an error on the "filename" option with "true" value 1`] = `
11 | "Mini CSS Extract Plugin Invalid Options
12 |
13 | options.filename should be string
14 | "
15 | `;
16 |
17 | exports[`validate options should throw an error on the "ignoreOrder" option with "1" value 1`] = `
18 | "Mini CSS Extract Plugin Invalid Options
19 |
20 | options.ignoreOrder should be boolean
21 | "
22 | `;
23 |
24 | exports[`validate options should throw an error on the "moduleFilename" option with "true" value 1`] = `
25 | "Mini CSS Extract Plugin Invalid Options
26 |
27 | options.moduleFilename should pass \\"instanceof\\" keyword validation
28 | "
29 | `;
30 |
--------------------------------------------------------------------------------
/test/cases/at-import/a.css:
--------------------------------------------------------------------------------
1 | @import './ae.css';
2 | @import './aa.css';
3 | @import './ab.css';
4 | @import './ac.css';
5 | @import './ad.css';
6 |
7 | body {
8 | background: red;
9 | }
10 |
--------------------------------------------------------------------------------
/test/cases/at-import/aa.css:
--------------------------------------------------------------------------------
1 | .aa {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/at-import/ab.css:
--------------------------------------------------------------------------------
1 | .ab {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/at-import/ac.css:
--------------------------------------------------------------------------------
1 | .ac {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/at-import/ad.css:
--------------------------------------------------------------------------------
1 | .ad {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/at-import/ae.css:
--------------------------------------------------------------------------------
1 | .ae {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/at-import/b.css:
--------------------------------------------------------------------------------
1 | @import './ba.css';
2 | @import './bb.css';
3 |
4 | body {
5 | background: yellow;
6 | }
7 |
--------------------------------------------------------------------------------
/test/cases/at-import/ba.css:
--------------------------------------------------------------------------------
1 | .ba {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/at-import/bb.css:
--------------------------------------------------------------------------------
1 | .bb {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/at-import/expected/main.css:
--------------------------------------------------------------------------------
1 | .ae {
2 | background: green;
3 | }
4 |
5 | .aa {
6 | background: green;
7 | }
8 |
9 | .ab {
10 | background: green;
11 | }
12 |
13 | .ac {
14 | background: green;
15 | }
16 |
17 | .ad {
18 | background: green;
19 | }
20 |
21 | body {
22 | background: red;
23 | }
24 |
25 | .ba {
26 | background: green;
27 | }
28 |
29 | .bb {
30 | background: green;
31 | }
32 |
33 | body {
34 | background: yellow;
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/test/cases/at-import/index.js:
--------------------------------------------------------------------------------
1 | import './a.css';
2 | import './b.css';
3 |
--------------------------------------------------------------------------------
/test/cases/at-import/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/chunkFilename/async.css:
--------------------------------------------------------------------------------
1 | .async {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/chunkFilename/expected/1.async.css:
--------------------------------------------------------------------------------
1 | .async {
2 | color: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/chunkFilename/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/chunkFilename/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
3 | /* eslint-disable-next-line no-unused-expressions */
4 | import(/* webpackChunkName: "async" */ './async.css');
5 |
--------------------------------------------------------------------------------
/test/cases/chunkFilename/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/chunkFilename/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | chunkFilename: '[id].[name].css',
17 | }),
18 | ],
19 | };
20 |
--------------------------------------------------------------------------------
/test/cases/commonjs-module-syntax/expected/main.css:
--------------------------------------------------------------------------------
1 | .foo__style__a {
2 | background: red;
3 | }
4 |
5 | .foo__style__b {
6 | color: green;
7 | }
8 |
9 | .c {
10 | color: blue;
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/test/cases/commonjs-module-syntax/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/commonjs-module-syntax/style.css:
--------------------------------------------------------------------------------
1 | .a {
2 | background: red;
3 | }
4 |
5 | :local(.b) {
6 | color: green;
7 | }
8 |
9 | :global(.c) {
10 | color: blue;
11 | }
12 |
--------------------------------------------------------------------------------
/test/cases/commonjs-module-syntax/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | {
11 | loader: Self.loader,
12 | options: { esModule: false },
13 | },
14 | {
15 | loader: 'css-loader',
16 | options: {
17 | modules: {
18 | mode: 'local',
19 | localIdentName: 'foo__[name]__[local]',
20 | },
21 | },
22 | },
23 | ],
24 | },
25 | ],
26 | },
27 | plugins: [
28 | new Self({
29 | filename: '[name].css',
30 | }),
31 | ],
32 | };
33 |
--------------------------------------------------------------------------------
/test/cases/composes-async/async-1.css:
--------------------------------------------------------------------------------
1 | :local .base {
2 | composes: composed from './async-2.css';
3 | background: blue;
4 | }
5 |
--------------------------------------------------------------------------------
/test/cases/composes-async/async-2.css:
--------------------------------------------------------------------------------
1 | :local .composed {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/composes-async/expected/async-1.css:
--------------------------------------------------------------------------------
1 | .base {
2 | background: blue;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/composes-async/expected/dedupe.css:
--------------------------------------------------------------------------------
1 | .composed {
2 | background: green;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/composes-async/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable-next-line no-unused-expressions */
2 | import(/* webpackChunkName: "async-1" */ './async-1.css');
3 | /* eslint-disable-next-line no-unused-expressions */
4 | import(/* webpackChunkName: "async-2" */ './async-2.css');
5 |
--------------------------------------------------------------------------------
/test/cases/composes-async/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | Self.loader,
11 | {
12 | loader: 'css-loader',
13 | options: {
14 | modules: {
15 | localIdentName: '[local]',
16 | },
17 | },
18 | },
19 | ],
20 | },
21 | ],
22 | },
23 | optimization: {
24 | splitChunks: {
25 | cacheGroups: {
26 | cssDedupe: {
27 | test: /\.css$/,
28 | name: 'dedupe',
29 | chunks: 'all',
30 | minChunks: 2,
31 | enforce: true,
32 | },
33 | },
34 | },
35 | },
36 | plugins: [
37 | new Self({
38 | filename: '[name].css',
39 | }),
40 | ],
41 | };
42 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/entryA.js:
--------------------------------------------------------------------------------
1 | import './styleA.css';
2 | import './styleB.css';
3 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/entryB.js:
--------------------------------------------------------------------------------
1 | import './styleA.css';
2 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/entryC.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faceyspacey/extract-css-chunks-webpack-plugin/18837c2ddc4175313cfd812698e7fae4ae4a7acc/test/cases/contenthash-multiple-entries/entryC.js
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/entryD.js:
--------------------------------------------------------------------------------
1 | import './styleA.css';
2 | import './styleB.css';
3 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/entryE.js:
--------------------------------------------------------------------------------
1 | import './styleC.css';
2 | import './styleD.css';
3 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/expected/96236f7f51b351aabd20.css:
--------------------------------------------------------------------------------
1 | .styleA {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/expected/f22bc5a793a5a86ad253.css:
--------------------------------------------------------------------------------
1 | .styleA {
2 | background: red;
3 | }
4 |
5 | .styleB {
6 | background: blue;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/styleA.css:
--------------------------------------------------------------------------------
1 | .styleA {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/styleB.css:
--------------------------------------------------------------------------------
1 | .styleB {
2 | background: blue;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/styleC.css:
--------------------------------------------------------------------------------
1 | .styleA {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/styleD.css:
--------------------------------------------------------------------------------
1 | .styleB {
2 | background: blue;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/contenthash-multiple-entries/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: {
5 | entryA: './entryA.js',
6 | entryB: './entryB.js',
7 | entryC: './entryC.js',
8 | entryD: './entryD.js',
9 | entryE: './entryE.js',
10 | },
11 | module: {
12 | rules: [
13 | {
14 | test: /\.css$/,
15 | use: [Self.loader, 'css-loader'],
16 | },
17 | ],
18 | },
19 | output: {
20 | filename: '[name]-[contenthash].js',
21 | },
22 | plugins: [
23 | new Self({
24 | filename: '[contenthash].css',
25 | }),
26 | ],
27 | };
28 |
--------------------------------------------------------------------------------
/test/cases/contenthash/expected/1.main.c4d90d38e7a606ae4d4c.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/contenthash/expected/2.main.64d1032b1547f22458a7.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/contenthash/index.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-unresolved
2 | import './style.css';
3 |
--------------------------------------------------------------------------------
/test/cases/contenthash/style1.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/contenthash/style2.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/contenthash/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = [1, 2].map((n) => {
4 | return {
5 | entry: './index.js',
6 | module: {
7 | rules: [
8 | {
9 | test: /\.css$/,
10 | use: [Self.loader, 'css-loader'],
11 | },
12 | ],
13 | },
14 | output: {
15 | filename: `${n}.[name].js`,
16 | },
17 | resolve: {
18 | alias: {
19 | './style.css': `./style${n}.css`,
20 | },
21 | },
22 | plugins: [
23 | new Self({
24 | filename: `${n}.[name].[contenthash].css`,
25 | }),
26 | ],
27 | };
28 | });
29 |
--------------------------------------------------------------------------------
/test/cases/css-import/a.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/css-import/b.css:
--------------------------------------------------------------------------------
1 | .b {
2 | background: red;
3 | }
4 |
5 | @import url('https://some/external/css');
6 |
7 | .b {
8 | color: yellow;
9 | }
10 |
--------------------------------------------------------------------------------
/test/cases/css-import/c.css:
--------------------------------------------------------------------------------
1 | .c {
2 | background: red;
3 | }
4 | @import './a.css';
5 | @import url('https://some/other/external/css');
6 |
7 | .c {
8 | color: yellow;
9 | }
10 |
--------------------------------------------------------------------------------
/test/cases/css-import/expected/main.css:
--------------------------------------------------------------------------------
1 | @import url(https://some/other/external/css);
2 | @import url(https://some/external/css);
3 | body {
4 | background: red;
5 | }
6 |
7 | .c {
8 | background: red;
9 | }
10 |
11 | .c {
12 | color: yellow;
13 | }
14 |
15 | .b {
16 | background: red;
17 | }
18 |
19 | .b {
20 | color: yellow;
21 | }
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/test/cases/css-import/index.css:
--------------------------------------------------------------------------------
1 | @import './c.css';
2 | @import './b.css';
3 |
--------------------------------------------------------------------------------
/test/cases/css-import/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.css',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/default-options/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/default-options/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/default-options/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/default-options/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [new Self()],
14 | };
15 |
--------------------------------------------------------------------------------
/test/cases/es-module-syntax/expected/main.css:
--------------------------------------------------------------------------------
1 | .foo__style__a {
2 | background: red;
3 | }
4 |
5 | .foo__style__b {
6 | color: green;
7 | }
8 |
9 | .c {
10 | color: blue;
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/test/cases/es-module-syntax/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/es-module-syntax/style.css:
--------------------------------------------------------------------------------
1 | .a {
2 | background: red;
3 | }
4 |
5 | :local(.b) {
6 | color: green;
7 | }
8 |
9 | :global(.c) {
10 | color: blue;
11 | }
12 |
--------------------------------------------------------------------------------
/test/cases/es-module-syntax/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | {
11 | loader: Self.loader,
12 | options: { esModule: true },
13 | },
14 | {
15 | loader: 'css-loader',
16 | options: {
17 | modules: {
18 | mode: 'local',
19 | localIdentName: 'foo__[name]__[local]',
20 | },
21 | },
22 | },
23 | ],
24 | },
25 | ],
26 | },
27 | plugins: [
28 | new Self({
29 | filename: '[name].css',
30 | }),
31 | ],
32 | };
33 |
--------------------------------------------------------------------------------
/test/cases/filename-with-template/async.css:
--------------------------------------------------------------------------------
1 | .async {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/filename-with-template/expected/async.css:
--------------------------------------------------------------------------------
1 | .async {
2 | color: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/filename-with-template/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/filename-with-template/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
3 | /* eslint-disable-next-line no-unused-expressions */
4 | import(/* webpackChunkName: "async" */ './async.css');
5 |
--------------------------------------------------------------------------------
/test/cases/filename-with-template/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/filename-with-template/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/filename-without-template/async.css:
--------------------------------------------------------------------------------
1 | .async {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/filename-without-template/expected/1.main.css:
--------------------------------------------------------------------------------
1 | .async {
2 | color: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/filename-without-template/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/filename-without-template/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
3 | /* eslint-disable-next-line no-unused-expressions */
4 | import(/* webpackChunkName: "async" */ './async.css');
5 |
--------------------------------------------------------------------------------
/test/cases/filename-without-template/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/filename-without-template/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: 'main.css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/hmr/a.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/hmr/b.css:
--------------------------------------------------------------------------------
1 | .b {
2 | background: red;
3 | }
4 |
5 | @import url('https://some/external/css');
6 |
7 | .b {
8 | color: yellow;
9 | }
10 |
--------------------------------------------------------------------------------
/test/cases/hmr/c.css:
--------------------------------------------------------------------------------
1 | .c {
2 | background: red;
3 | }
4 | @import './a.css';
5 | @import url('https://some/other/external/css');
6 |
7 | .c {
8 | color: yellow;
9 | }
10 |
--------------------------------------------------------------------------------
/test/cases/hmr/expected/webpack-4/main.css:
--------------------------------------------------------------------------------
1 | @import url(https://some/other/external/css);
2 | @import url(https://some/external/css);
3 | body {
4 | background: red;
5 | }
6 |
7 | .c {
8 | background: red;
9 | }
10 |
11 | .c {
12 | color: yellow;
13 | }
14 |
15 | .b {
16 | background: red;
17 | }
18 |
19 | .b {
20 | color: yellow;
21 | }
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/test/cases/hmr/expected/webpack-4/main.js:
--------------------------------------------------------------------------------
1 | /******/ (function(modules) { // webpackBootstrap
2 | /******/ // The module cache
3 | /******/ var installedModules = {};
4 | /******/
5 | /******/ // The require function
6 | /******/ function __webpack_require__(moduleId) {
7 | /******/
8 | /******/ // Check if module is in cache
9 | /******/ if(installedModules[moduleId]) {
10 | /******/ return installedModules[moduleId].exports;
11 | /******/ }
12 | /******/ // Create a new module (and put it into the cache)
13 | /******/ var module = installedModules[moduleId] = {
14 | /******/ i: moduleId,
15 | /******/ l: false,
16 | /******/ exports: {}
17 | /******/ };
18 | /******/
19 | /******/ // Execute the module function
20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21 | /******/
22 | /******/ // Flag the module as loaded
23 | /******/ module.l = true;
24 | /******/
25 | /******/ // Return the exports of the module
26 | /******/ return module.exports;
27 | /******/ }
28 | /******/
29 | /******/
30 | /******/ // expose the modules object (__webpack_modules__)
31 | /******/ __webpack_require__.m = modules;
32 | /******/
33 | /******/ // expose the module cache
34 | /******/ __webpack_require__.c = installedModules;
35 | /******/
36 | /******/ // define getter function for harmony exports
37 | /******/ __webpack_require__.d = function(exports, name, getter) {
38 | /******/ if(!__webpack_require__.o(exports, name)) {
39 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
40 | /******/ }
41 | /******/ };
42 | /******/
43 | /******/ // define __esModule on exports
44 | /******/ __webpack_require__.r = function(exports) {
45 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
46 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
47 | /******/ }
48 | /******/ Object.defineProperty(exports, '__esModule', { value: true });
49 | /******/ };
50 | /******/
51 | /******/ // create a fake namespace object
52 | /******/ // mode & 1: value is a module id, require it
53 | /******/ // mode & 2: merge all properties of value into the ns
54 | /******/ // mode & 4: return value when already ns object
55 | /******/ // mode & 8|1: behave like require
56 | /******/ __webpack_require__.t = function(value, mode) {
57 | /******/ if(mode & 1) value = __webpack_require__(value);
58 | /******/ if(mode & 8) return value;
59 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
60 | /******/ var ns = Object.create(null);
61 | /******/ __webpack_require__.r(ns);
62 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
63 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
64 | /******/ return ns;
65 | /******/ };
66 | /******/
67 | /******/ // getDefaultExport function for compatibility with non-harmony modules
68 | /******/ __webpack_require__.n = function(module) {
69 | /******/ var getter = module && module.__esModule ?
70 | /******/ function getDefault() { return module['default']; } :
71 | /******/ function getModuleExports() { return module; };
72 | /******/ __webpack_require__.d(getter, 'a', getter);
73 | /******/ return getter;
74 | /******/ };
75 | /******/
76 | /******/ // Object.prototype.hasOwnProperty.call
77 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
78 | /******/
79 | /******/ // __webpack_public_path__
80 | /******/ __webpack_require__.p = "";
81 | /******/
82 | /******/
83 | /******/ // Load entry module and return exports
84 | /******/ return __webpack_require__(__webpack_require__.s = 0);
85 | /******/ })
86 | /************************************************************************/
87 | /******/ ([
88 | /* 0 */
89 | /***/ (function(module, exports, __webpack_require__) {
90 |
91 | // extracted by extract-css-chunks-webpack-plugin
92 | if(false) { var cssReload; }
93 |
94 |
95 | /***/ })
96 | /******/ ]);
--------------------------------------------------------------------------------
/test/cases/hmr/expected/webpack-5/main.css:
--------------------------------------------------------------------------------
1 | @import url(https://some/other/external/css);
2 | @import url(https://some/external/css);
3 | body {
4 | background: red;
5 | }
6 |
7 | .c {
8 | background: red;
9 | }
10 |
11 | .c {
12 | color: yellow;
13 | }
14 |
15 | .b {
16 | background: red;
17 | }
18 |
19 | .b {
20 | color: yellow;
21 | }
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/test/cases/hmr/expected/webpack-5/main.js:
--------------------------------------------------------------------------------
1 | /******/ (() => { // webpackBootstrap
2 | /******/ /************************************************************************/
3 | // extracted by extract-css-chunks-webpack-plugin
4 | if(false) { var cssReload; }
5 |
6 | /******/ })()
7 | ;
8 |
--------------------------------------------------------------------------------
/test/cases/hmr/index.css:
--------------------------------------------------------------------------------
1 | @import './c.css';
2 | @import './b.css';
3 |
--------------------------------------------------------------------------------
/test/cases/hmr/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.css',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | {
11 | loader: Self.loader,
12 | options: {
13 | hmr: true,
14 | },
15 | },
16 | 'css-loader',
17 | ],
18 | },
19 | ],
20 | },
21 | plugins: [
22 | new Self({
23 | filename: '[name].css',
24 | }),
25 | ],
26 | };
27 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrder/e1.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e1';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrder/e2.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e2';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrder/expected/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e2';
3 | }
4 |
5 | body {
6 | content: 'e1';
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrder/index.js:
--------------------------------------------------------------------------------
1 | import './e2.css';
2 | import './e1.css';
3 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrder/index2.js:
--------------------------------------------------------------------------------
1 | import './e1.css';
2 | import './e2.css';
3 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrder/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: {
5 | entry1: './index.js',
6 | entry2: './index2.js',
7 | },
8 | module: {
9 | rules: [
10 | {
11 | test: /\.css$/,
12 | use: [Self.loader, 'css-loader'],
13 | },
14 | ],
15 | },
16 | optimization: {
17 | splitChunks: {
18 | cacheGroups: {
19 | styles: {
20 | name: 'styles',
21 | chunks: 'all',
22 | test: /\.css$/,
23 | enforce: true,
24 | },
25 | },
26 | },
27 | },
28 | plugins: [
29 | new Self({
30 | ignoreOrder: true,
31 | }),
32 | ],
33 | };
34 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalse/e1.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e1';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalse/e2.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e2';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalse/e3.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e3';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalse/expected/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e2';
3 | }
4 |
5 | body {
6 | content: 'e1';
7 | }
8 |
9 | body {
10 | content: 'e3';
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalse/index.js:
--------------------------------------------------------------------------------
1 | import './e2.css';
2 | import './e1.css';
3 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalse/index2.js:
--------------------------------------------------------------------------------
1 | import './e1.css';
2 | import './e2.css';
3 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalse/index3.js:
--------------------------------------------------------------------------------
1 | import './e2.css';
2 | import './e3.css';
3 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalse/warnings.js:
--------------------------------------------------------------------------------
1 | const cssLoaderPath = require.resolve('css-loader').replace(/\\/g, '/');
2 |
3 | module.exports = [
4 | '',
5 | 'WARNING in chunk styles [extract-css-chunks-webpack-plugin]',
6 | 'Conflicting order. Following module has been added:',
7 | ` * css ${cssLoaderPath}!./e2.css`,
8 | 'despite it was not able to fulfill desired ordering with these modules:',
9 | ` * css ${cssLoaderPath}!./e1.css`,
10 | " - couldn't fulfill desired order of chunk group(s) entry2",
11 | ' - while fulfilling desired order of chunk group(s) entry1',
12 | ].join('\n');
13 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalse/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: {
5 | entry1: './index.js',
6 | entry2: './index2.js',
7 | entry3: './index3.js',
8 | },
9 | module: {
10 | rules: [
11 | {
12 | test: /\.css$/,
13 | use: [Self.loader, 'css-loader'],
14 | },
15 | ],
16 | },
17 | optimization: {
18 | splitChunks: {
19 | cacheGroups: {
20 | styles: {
21 | name: 'styles',
22 | chunks: 'all',
23 | test: /\.css$/,
24 | enforce: true,
25 | },
26 | },
27 | },
28 | },
29 | plugins: [
30 | new Self({
31 | ignoreOrder: false,
32 | }),
33 | ],
34 | };
35 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/e1.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e1';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/e2.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e2';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/e3.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e3';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/e4.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e4';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/expected/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e1';
3 | }
4 |
5 | body {
6 | content: 'e4';
7 | }
8 |
9 | body {
10 | content: 'e2';
11 | }
12 |
13 | body {
14 | content: 'e3';
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/index.js:
--------------------------------------------------------------------------------
1 | import './e1.css';
2 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/index2.js:
--------------------------------------------------------------------------------
1 | import './e2.css';
2 | import './e1.css';
3 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/index3.js:
--------------------------------------------------------------------------------
1 | import './e3.css';
2 | import './e4.css';
3 | import './e2.css';
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/index4.js:
--------------------------------------------------------------------------------
1 | import './e4.css';
2 | import './e2.css';
3 | import './e3.css';
4 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/warnings.js:
--------------------------------------------------------------------------------
1 | const cssLoaderPath = require.resolve('css-loader').replace(/\\/g, '/');
2 |
3 | module.exports = [
4 | '',
5 | 'WARNING in chunk styles [extract-css-chunks-webpack-plugin]',
6 | 'Conflicting order. Following module has been added:',
7 | ` * css ${cssLoaderPath}!./e1.css`,
8 | 'despite it was not able to fulfill desired ordering with these modules:',
9 | ` * css ${cssLoaderPath}!./e2.css`,
10 | " - couldn't fulfill desired order of chunk group(s) entry2",
11 | '',
12 | 'WARNING in chunk styles [extract-css-chunks-webpack-plugin]',
13 | 'Conflicting order. Following module has been added:',
14 | ` * css ${cssLoaderPath}!./e4.css`,
15 | 'despite it was not able to fulfill desired ordering with these modules:',
16 | ` * css ${cssLoaderPath}!./e3.css`,
17 | " - couldn't fulfill desired order of chunk group(s) entry3",
18 | ' - while fulfilling desired order of chunk group(s) entry4',
19 | '',
20 | 'WARNING in chunk styles [extract-css-chunks-webpack-plugin]',
21 | 'Conflicting order. Following module has been added:',
22 | ` * css ${cssLoaderPath}!./e2.css`,
23 | 'despite it was not able to fulfill desired ordering with these modules:',
24 | ` * css ${cssLoaderPath}!./e3.css`,
25 | " - couldn't fulfill desired order of chunk group(s) entry3",
26 | ' - while fulfilling desired order of chunk group(s) entry4',
27 | ].join('\n');
28 |
--------------------------------------------------------------------------------
/test/cases/ignoreOrderFalseWithoutGoodChunks/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: {
5 | entry1: './index.js',
6 | entry2: './index2.js',
7 | entry3: './index3.js',
8 | entry4: './index4.js',
9 | },
10 | module: {
11 | rules: [
12 | {
13 | test: /\.css$/,
14 | use: [Self.loader, 'css-loader'],
15 | },
16 | ],
17 | },
18 | optimization: {
19 | splitChunks: {
20 | cacheGroups: {
21 | styles: {
22 | name: 'styles',
23 | chunks: 'all',
24 | test: /\.css$/,
25 | enforce: true,
26 | },
27 | },
28 | },
29 | },
30 | plugins: [
31 | new Self({
32 | ignoreOrder: false,
33 | }),
34 | ],
35 | };
36 |
--------------------------------------------------------------------------------
/test/cases/import/a.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/import/b.css:
--------------------------------------------------------------------------------
1 | .b {
2 | background: red;
3 | }
4 |
5 | @import url('https://some/external/css');
6 |
7 | .b {
8 | color: yellow;
9 | }
10 |
--------------------------------------------------------------------------------
/test/cases/import/c.css:
--------------------------------------------------------------------------------
1 | .c {
2 | background: red;
3 | }
4 |
5 | @import url('https://some/other/external/css');
6 |
7 | .c {
8 | color: yellow;
9 | }
10 |
--------------------------------------------------------------------------------
/test/cases/import/expected/main.css:
--------------------------------------------------------------------------------
1 | @import url(https://some/other/external/css);
2 | @import url(https://some/external/css);
3 | .c {
4 | background: red;
5 | }
6 |
7 | .c {
8 | color: yellow;
9 | }
10 |
11 | body {
12 | background: red;
13 | }
14 |
15 | .b {
16 | background: red;
17 | }
18 |
19 | .b {
20 | color: yellow;
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/test/cases/import/index.js:
--------------------------------------------------------------------------------
1 | import './c.css';
2 | import './a.css';
3 | import './b.css';
4 |
--------------------------------------------------------------------------------
/test/cases/import/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/insert-function/expected/1.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/insert-function/expected/1.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[1],[
2 | /* 0 */,
3 | /* 1 */
4 | /***/ (function(module, exports, __webpack_require__) {
5 |
6 | // extracted by extract-css-chunks-webpack-plugin
7 |
8 | /***/ })
9 | ]]);
--------------------------------------------------------------------------------
/test/cases/insert-function/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | extract-css-chunks-webpack-plugin testcase
7 |
8 |
9 |
21 |
26 |
27 |
28 |
29 |
30 | Initial CSS: Must be green
31 |
32 |
33 |
Hot Module Replacement
34 |
RED
35 |
GREEN
36 |
BLUE
37 |
38 |
39 |
Hot Module Replacement + CSS modules
40 |
RED
41 |
GREEN
42 |
BLUE
43 |
44 |
45 |
46 | Lazy CSS: Must be red, but turn green when
47 | .
48 |
49 |
50 | But turn orange, when
51 | . Additional
52 | clicks have no effect.
53 |
54 |
55 | Refresh and press buttons in reverse order: This should turn green
56 | instead.
57 |
58 |
59 |
60 |
61 | Lazy CSS: Turn off the network and
62 | .
63 |
64 |
An error should have appeared.
65 |
66 | Now if you turn the network back on and click it again, it should turn
67 | aqua.
68 |
69 |
70 |
71 |
Preloaded CSS: Must be green.
72 |
73 | displays
74 | an alert and should turn red.
75 |
76 |
77 |
78 |
Preloaded inlined CSS: Must be green.
79 |
80 | displays
81 | an alert and should turn red.
82 |
83 |
84 |
85 |
CrossOriginLoading Option: Must be red.
86 |
87 | loads chunks with crossorigin
88 | attribute and should turn green.
89 |
90 |
91 |
92 |
93 |
94 | zack
95 |
96 |
--------------------------------------------------------------------------------
/test/cases/insert-function/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 |
3 | // eslint-disable-next-line
4 | import('./inject.css');
5 |
--------------------------------------------------------------------------------
/test/cases/insert-function/src/inject.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/insert-function/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/insert-function/webpack.config.e2e.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const Self = require('../../../');
4 |
5 | const ENABLE_HMR =
6 | typeof process.env.ENABLE_HMR !== 'undefined'
7 | ? Boolean(process.env.ENABLE_HMR)
8 | : false;
9 |
10 | const ENABLE_ES_MODULE =
11 | typeof process.env.ES_MODULE !== 'undefined'
12 | ? Boolean(process.env.ES_MODULE)
13 | : false;
14 |
15 | module.exports = {
16 | mode: 'development',
17 | output: {
18 | path: path.resolve(__dirname, 'expected'),
19 | chunkFilename: '[contenthash].js',
20 | publicPath: '/',
21 | crossOriginLoading: 'anonymous',
22 | },
23 | module: {
24 | rules: [
25 | {
26 | test: /\.css$/,
27 | exclude: [/\.module\.css$/i],
28 | use: [
29 | {
30 | loader: Self.loader,
31 | options: {
32 | hmr: ENABLE_HMR,
33 | },
34 | },
35 | {
36 | loader: 'css-loader',
37 | options: {
38 | esModule: ENABLE_ES_MODULE,
39 | },
40 | },
41 | ],
42 | },
43 | {
44 | test: /\.module\.css$/i,
45 | use: [
46 | {
47 | loader: Self.loader,
48 | options: {
49 | hmr: ENABLE_HMR,
50 | },
51 | },
52 | {
53 | loader: 'css-loader',
54 | options: {
55 | modules: true,
56 | esModule: ENABLE_ES_MODULE,
57 | },
58 | },
59 | ],
60 | },
61 | ],
62 | },
63 | plugins: [
64 | new Self({
65 | filename: '[name].css',
66 | chunkFilename: '[id].css',
67 | insert: (linkTag) => {
68 | document.head.appendChild(linkTag)
69 | },
70 | }),
71 | ],
72 | devServer: {
73 | contentBase: __dirname,
74 | port: 3001,
75 | headers: {
76 | 'Access-Control-Allow-Origin': '*',
77 | },
78 | },
79 | };
80 |
--------------------------------------------------------------------------------
/test/cases/insert-function/webpack.config.js:
--------------------------------------------------------------------------------
1 | /* global document */
2 |
3 | const Self = require('../../../');
4 |
5 | const ENABLE_HMR =
6 | typeof process.env.ENABLE_HMR !== 'undefined'
7 | ? Boolean(process.env.ENABLE_HMR)
8 | : false;
9 |
10 | const ENABLE_ES_MODULE =
11 | typeof process.env.ES_MODULE !== 'undefined'
12 | ? Boolean(process.env.ES_MODULE)
13 | : false;
14 |
15 | module.exports = {
16 | module: {
17 | rules: [
18 | {
19 | test: /\.css$/,
20 | exclude: [/\.module\.css$/i],
21 | use: [
22 | {
23 | loader: Self.loader,
24 | options: {
25 | hmr: ENABLE_HMR,
26 | },
27 | },
28 | {
29 | loader: 'css-loader',
30 | options: {
31 | esModule: ENABLE_ES_MODULE,
32 | },
33 | },
34 | ],
35 | },
36 | {
37 | test: /\.module\.css$/i,
38 | use: [
39 | {
40 | loader: Self.loader,
41 | options: {
42 | hmr: ENABLE_HMR,
43 | },
44 | },
45 | {
46 | loader: 'css-loader',
47 | options: {
48 | modules: true,
49 | esModule: ENABLE_ES_MODULE,
50 | },
51 | },
52 | ],
53 | },
54 | ],
55 | },
56 | plugins: [
57 | new Self({
58 | filename: '[name].css',
59 | chunkFilename: '[id].css',
60 | insert: function insert(linkTag) {
61 | const reference = document.querySelector('.hot-reload');
62 | if (reference) {
63 | reference.parentNode.insertBefore(linkTag, reference);
64 | }
65 | },
66 | }),
67 | ],
68 | };
69 |
--------------------------------------------------------------------------------
/test/cases/insert-string/expected/1.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/insert-string/expected/1.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[1],[
2 | /* 0 */,
3 | /* 1 */
4 | /***/ (function(module, exports, __webpack_require__) {
5 |
6 | // extracted by extract-css-chunks-webpack-plugin
7 |
8 | /***/ })
9 | ]]);
--------------------------------------------------------------------------------
/test/cases/insert-string/expected/main.js:
--------------------------------------------------------------------------------
1 | /******/ (function(modules) { // webpackBootstrap
2 | /******/ // install a JSONP callback for chunk loading
3 | /******/ function webpackJsonpCallback(data) {
4 | /******/ var chunkIds = data[0];
5 | /******/ var moreModules = data[1];
6 | /******/
7 | /******/
8 | /******/ // add "moreModules" to the modules object,
9 | /******/ // then flag all "chunkIds" as loaded and fire callback
10 | /******/ var moduleId, chunkId, i = 0, resolves = [];
11 | /******/ for(;i < chunkIds.length; i++) {
12 | /******/ chunkId = chunkIds[i];
13 | /******/ if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
14 | /******/ resolves.push(installedChunks[chunkId][0]);
15 | /******/ }
16 | /******/ installedChunks[chunkId] = 0;
17 | /******/ }
18 | /******/ for(moduleId in moreModules) {
19 | /******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
20 | /******/ modules[moduleId] = moreModules[moduleId];
21 | /******/ }
22 | /******/ }
23 | /******/ if(parentJsonpFunction) parentJsonpFunction(data);
24 | /******/
25 | /******/ while(resolves.length) {
26 | /******/ resolves.shift()();
27 | /******/ }
28 | /******/
29 | /******/ };
30 | /******/
31 | /******/
32 | /******/ // The module cache
33 | /******/ var installedModules = {};
34 | /******/
35 | /******/ // object to store loaded CSS chunks
36 | /******/ var installedCssChunks = {
37 | /******/ 0: 0
38 | /******/ }
39 | /******/
40 | /******/ // object to store loaded and loading chunks
41 | /******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
42 | /******/ // Promise = chunk loading, 0 = chunk loaded
43 | /******/ var installedChunks = {
44 | /******/ 0: 0
45 | /******/ };
46 | /******/
47 | /******/
48 | /******/
49 | /******/ // script path function
50 | /******/ function jsonpScriptSrc(chunkId) {
51 | /******/ return __webpack_require__.p + "" + ({}[chunkId]||chunkId) + ".js"
52 | /******/ }
53 | /******/
54 | /******/ // The require function
55 | /******/ function __webpack_require__(moduleId) {
56 | /******/
57 | /******/ // Check if module is in cache
58 | /******/ if(installedModules[moduleId]) {
59 | /******/ return installedModules[moduleId].exports;
60 | /******/ }
61 | /******/ // Create a new module (and put it into the cache)
62 | /******/ var module = installedModules[moduleId] = {
63 | /******/ i: moduleId,
64 | /******/ l: false,
65 | /******/ exports: {}
66 | /******/ };
67 | /******/
68 | /******/ // Execute the module function
69 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
70 | /******/
71 | /******/ // Flag the module as loaded
72 | /******/ module.l = true;
73 | /******/
74 | /******/ // Return the exports of the module
75 | /******/ return module.exports;
76 | /******/ }
77 | /******/
78 | /******/ // This file contains only the entry chunk.
79 | /******/ // The chunk loading function for additional chunks
80 | /******/ __webpack_require__.e = function requireEnsure(chunkId) {
81 | /******/ var promises = [];
82 | /******/
83 | /******/
84 | /******/ // extract-css-chunks-webpack-plugin CSS loading
85 | /******/ var supportsPreload = (function() { try { return document.createElement("link").relList.supports("preload"); } catch(e) { return false; }}());
86 | /******/ var cssChunks = {"1":1};
87 | /******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);
88 | /******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {
89 | /******/ promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {
90 | /******/ var href = "" + chunkId + ".css";
91 | /******/ var fullhref = __webpack_require__.p + href;
92 | /******/ var existingLinkTags = document.getElementsByTagName("link");
93 | /******/ for(var i = 0; i < existingLinkTags.length; i++) {
94 | /******/ var tag = existingLinkTags[i];
95 | /******/ var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");
96 | /******/ if((tag.rel === "stylesheet" || tag.rel === "preload") && (dataHref === href || dataHref === fullhref)) return resolve();
97 | /******/ }
98 | /******/ var existingStyleTags = document.getElementsByTagName("style");
99 | /******/ for(var i = 0; i < existingStyleTags.length; i++) {
100 | /******/ var tag = existingStyleTags[i];
101 | /******/ var dataHref = tag.getAttribute("data-href");
102 | /******/ if(dataHref === href || dataHref === fullhref) return resolve();
103 | /******/ }
104 | /******/ var linkTag = document.createElement("link");
105 | /******/ linkTag.rel = supportsPreload ? "preload": "stylesheet";
106 | /******/ supportsPreload ? linkTag.as = "style" : linkTag.type = "text/css";
107 | /******/ linkTag.onload = resolve;
108 | /******/ linkTag.onerror = function(event) {
109 | /******/ var request = event && event.target && event.target.src || fullhref;
110 | /******/ var err = new Error("Loading CSS chunk " + chunkId + " failed.\n(" + request + ")");
111 | /******/ err.code = "CSS_CHUNK_LOAD_FAILED";
112 | /******/ err.request = request;
113 | /******/ delete installedCssChunks[chunkId]
114 | /******/ linkTag.parentNode.removeChild(linkTag)
115 | /******/ reject(err);
116 | /******/ };
117 | /******/ linkTag.href = fullhref;
118 | /******/
119 | /******/ var insert = body;
120 | /******/ insert(linkTag);
121 | /******/ }).then(function() {
122 | /******/ installedCssChunks[chunkId] = 0;
123 | /******/ if(supportsPreload) {
124 | /******/ var execLinkTag = document.createElement("link");
125 | /******/ execLinkTag.href = __webpack_require__.p + "" + chunkId + ".css";
126 | /******/ execLinkTag.rel = "stylesheet";
127 | /******/ execLinkTag.type = "text/css";
128 | /******/ document.body.appendChild(execLinkTag);
129 | /******/ }
130 | /******/ }));
131 | /******/ }
132 | /******/
133 | /******/ // JSONP chunk loading for javascript
134 | /******/
135 | /******/ var installedChunkData = installedChunks[chunkId];
136 | /******/ if(installedChunkData !== 0) { // 0 means "already installed".
137 | /******/
138 | /******/ // a Promise means "currently loading".
139 | /******/ if(installedChunkData) {
140 | /******/ promises.push(installedChunkData[2]);
141 | /******/ } else {
142 | /******/ // setup Promise in chunk cache
143 | /******/ var promise = new Promise(function(resolve, reject) {
144 | /******/ installedChunkData = installedChunks[chunkId] = [resolve, reject];
145 | /******/ });
146 | /******/ promises.push(installedChunkData[2] = promise);
147 | /******/
148 | /******/ // start chunk loading
149 | /******/ var script = document.createElement('script');
150 | /******/ var onScriptComplete;
151 | /******/
152 | /******/ script.charset = 'utf-8';
153 | /******/ script.timeout = 120;
154 | /******/ if (__webpack_require__.nc) {
155 | /******/ script.setAttribute("nonce", __webpack_require__.nc);
156 | /******/ }
157 | /******/ script.src = jsonpScriptSrc(chunkId);
158 | /******/
159 | /******/ // create error before stack unwound to get useful stacktrace later
160 | /******/ var error = new Error();
161 | /******/ onScriptComplete = function (event) {
162 | /******/ // avoid mem leaks in IE.
163 | /******/ script.onerror = script.onload = null;
164 | /******/ clearTimeout(timeout);
165 | /******/ var chunk = installedChunks[chunkId];
166 | /******/ if(chunk !== 0) {
167 | /******/ if(chunk) {
168 | /******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
169 | /******/ var realSrc = event && event.target && event.target.src;
170 | /******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
171 | /******/ error.name = 'ChunkLoadError';
172 | /******/ error.type = errorType;
173 | /******/ error.request = realSrc;
174 | /******/ chunk[1](error);
175 | /******/ }
176 | /******/ installedChunks[chunkId] = undefined;
177 | /******/ }
178 | /******/ };
179 | /******/ var timeout = setTimeout(function(){
180 | /******/ onScriptComplete({ type: 'timeout', target: script });
181 | /******/ }, 120000);
182 | /******/ script.onerror = script.onload = onScriptComplete;
183 | /******/ document.head.appendChild(script);
184 | /******/ }
185 | /******/ }
186 | /******/ return Promise.all(promises);
187 | /******/ };
188 | /******/
189 | /******/ // expose the modules object (__webpack_modules__)
190 | /******/ __webpack_require__.m = modules;
191 | /******/
192 | /******/ // expose the module cache
193 | /******/ __webpack_require__.c = installedModules;
194 | /******/
195 | /******/ // define getter function for harmony exports
196 | /******/ __webpack_require__.d = function(exports, name, getter) {
197 | /******/ if(!__webpack_require__.o(exports, name)) {
198 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
199 | /******/ }
200 | /******/ };
201 | /******/
202 | /******/ // define __esModule on exports
203 | /******/ __webpack_require__.r = function(exports) {
204 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
205 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
206 | /******/ }
207 | /******/ Object.defineProperty(exports, '__esModule', { value: true });
208 | /******/ };
209 | /******/
210 | /******/ // create a fake namespace object
211 | /******/ // mode & 1: value is a module id, require it
212 | /******/ // mode & 2: merge all properties of value into the ns
213 | /******/ // mode & 4: return value when already ns object
214 | /******/ // mode & 8|1: behave like require
215 | /******/ __webpack_require__.t = function(value, mode) {
216 | /******/ if(mode & 1) value = __webpack_require__(value);
217 | /******/ if(mode & 8) return value;
218 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
219 | /******/ var ns = Object.create(null);
220 | /******/ __webpack_require__.r(ns);
221 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
222 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
223 | /******/ return ns;
224 | /******/ };
225 | /******/
226 | /******/ // getDefaultExport function for compatibility with non-harmony modules
227 | /******/ __webpack_require__.n = function(module) {
228 | /******/ var getter = module && module.__esModule ?
229 | /******/ function getDefault() { return module['default']; } :
230 | /******/ function getModuleExports() { return module; };
231 | /******/ __webpack_require__.d(getter, 'a', getter);
232 | /******/ return getter;
233 | /******/ };
234 | /******/
235 | /******/ // Object.prototype.hasOwnProperty.call
236 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
237 | /******/
238 | /******/ // __webpack_public_path__
239 | /******/ __webpack_require__.p = "";
240 | /******/
241 | /******/ // on error function for async loading
242 | /******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
243 | /******/
244 | /******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
245 | /******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
246 | /******/ jsonpArray.push = webpackJsonpCallback;
247 | /******/ jsonpArray = jsonpArray.slice();
248 | /******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
249 | /******/ var parentJsonpFunction = oldJsonpFunction;
250 | /******/
251 | /******/
252 | /******/ // Load entry module and return exports
253 | /******/ return __webpack_require__(__webpack_require__.s = 0);
254 | /******/ })
255 | /************************************************************************/
256 | /******/ ([
257 | /* 0 */
258 | /***/ (function(module, exports, __webpack_require__) {
259 |
260 | /* eslint-env browser */
261 |
262 | // eslint-disable-next-line
263 | __webpack_require__.e(/* import() */ 1).then(__webpack_require__.t.bind(null, 1, 7));
264 |
265 |
266 | /***/ })
267 | /******/ ]);
--------------------------------------------------------------------------------
/test/cases/insert-string/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | extract-css-chunks-webpack-plugin testcase
7 |
8 |
9 |
21 |
26 |
27 |
28 |
29 |
30 | Initial CSS: Must be green
31 |
32 |
33 |
Hot Module Replacement
34 |
RED
35 |
GREEN
36 |
BLUE
37 |
38 |
39 |
Hot Module Replacement + CSS modules
40 |
RED
41 |
GREEN
42 |
BLUE
43 |
44 |
45 |
46 | Lazy CSS: Must be red, but turn green when
47 | .
48 |
49 |
50 | But turn orange, when
51 | . Additional
52 | clicks have no effect.
53 |
54 |
55 | Refresh and press buttons in reverse order: This should turn green
56 | instead.
57 |
58 |
59 |
60 |
61 | Lazy CSS: Turn off the network and
62 | .
63 |
64 |
An error should have appeared.
65 |
66 | Now if you turn the network back on and click it again, it should turn
67 | aqua.
68 |
69 |
70 |
71 |
Preloaded CSS: Must be green.
72 |
73 | displays
74 | an alert and should turn red.
75 |
76 |
77 |
78 |
Preloaded inlined CSS: Must be green.
79 |
80 | displays
81 | an alert and should turn red.
82 |
83 |
84 |
85 |
CrossOriginLoading Option: Must be red.
86 |
87 | loads chunks with crossorigin
88 | attribute and should turn green.
89 |
90 |
91 |
92 |
93 |
94 | zack
95 |
96 |
--------------------------------------------------------------------------------
/test/cases/insert-string/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 |
3 | // eslint-disable-next-line
4 | import('./inject.css');
5 |
--------------------------------------------------------------------------------
/test/cases/insert-string/src/inject.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/insert-string/webpack.config.e2e.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const Self = require('../../../');
4 |
5 | const ENABLE_HMR =
6 | typeof process.env.ENABLE_HMR !== 'undefined'
7 | ? Boolean(process.env.ENABLE_HMR)
8 | : false;
9 |
10 | const ENABLE_ES_MODULE =
11 | typeof process.env.ES_MODULE !== 'undefined'
12 | ? Boolean(process.env.ES_MODULE)
13 | : false;
14 |
15 | module.exports = {
16 | mode: 'development',
17 | output: {
18 | path: path.resolve(__dirname, 'expected'),
19 | chunkFilename: '[contenthash].js',
20 | publicPath: '/',
21 | crossOriginLoading: 'anonymous',
22 | },
23 | module: {
24 | rules: [
25 | {
26 | test: /\.css$/,
27 | exclude: [/\.module\.css$/i],
28 | use: [
29 | {
30 | loader: Self.loader,
31 | options: {
32 | hmr: ENABLE_HMR,
33 | },
34 | },
35 | {
36 | loader: 'css-loader',
37 | options: {
38 | esModule: ENABLE_ES_MODULE,
39 | },
40 | },
41 | ],
42 | },
43 | {
44 | test: /\.module\.css$/i,
45 | use: [
46 | {
47 | loader: Self.loader,
48 | options: {
49 | hmr: ENABLE_HMR,
50 | },
51 | },
52 | {
53 | loader: 'css-loader',
54 | options: {
55 | modules: true,
56 | esModule: ENABLE_ES_MODULE,
57 | },
58 | },
59 | ],
60 | },
61 | ],
62 | },
63 | plugins: [
64 | new Self({
65 | filename: '[name].css',
66 | chunkFilename: '[id].css',
67 | insert: '(linkTag) => { document.head.appendChild(linkTag) }',
68 | }),
69 | ],
70 | devServer: {
71 | contentBase: __dirname,
72 | port: 5000,
73 | headers: {
74 | 'Access-Control-Allow-Origin': '*',
75 | },
76 | },
77 | };
78 |
--------------------------------------------------------------------------------
/test/cases/insert-string/webpack.config.js:
--------------------------------------------------------------------------------
1 | const Self = require('../../../');
2 |
3 | const ENABLE_HMR =
4 | typeof process.env.ENABLE_HMR !== 'undefined'
5 | ? Boolean(process.env.ENABLE_HMR)
6 | : false;
7 |
8 | const ENABLE_ES_MODULE =
9 | typeof process.env.ES_MODULE !== 'undefined'
10 | ? Boolean(process.env.ES_MODULE)
11 | : false;
12 |
13 | module.exports = {
14 | module: {
15 | rules: [
16 | {
17 | test: /\.css$/,
18 | exclude: [/\.module\.css$/i],
19 | use: [
20 | {
21 | loader: Self.loader,
22 | options: {
23 | hmr: ENABLE_HMR,
24 | },
25 | },
26 | {
27 | loader: 'css-loader',
28 | options: {
29 | esModule: ENABLE_ES_MODULE,
30 | },
31 | },
32 | ],
33 | },
34 | {
35 | test: /\.module\.css$/i,
36 | use: [
37 | {
38 | loader: Self.loader,
39 | options: {
40 | hmr: ENABLE_HMR,
41 | },
42 | },
43 | {
44 | loader: 'css-loader',
45 | options: {
46 | modules: true,
47 | esModule: ENABLE_ES_MODULE,
48 | },
49 | },
50 | ],
51 | },
52 | ],
53 | },
54 | plugins: [
55 | new Self({
56 | filename: '[name].css',
57 | chunkFilename: '[id].css',
58 | insert: 'body',
59 | }),
60 | ],
61 | };
62 |
--------------------------------------------------------------------------------
/test/cases/js-hash/expected/style.922798e08e96756adb4a.1.css:
--------------------------------------------------------------------------------
1 | .wX52cuPepLZcpDx5S3yYO {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/js-hash/expected/style.fe78b7a6c50df391f00c.2.css:
--------------------------------------------------------------------------------
1 |
2 | .wX52cuPepLZcpDx5S3yYO {
3 | background: green;
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/test/cases/js-hash/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable-next-line no-unused-expressions */
2 | import(/* webpackChunkName: "style" */ './style.css');
3 |
--------------------------------------------------------------------------------
/test/cases/js-hash/loader.js:
--------------------------------------------------------------------------------
1 | module.exports = function loader(source) {
2 | const { number } = this.query;
3 | return source.split(/\/\* break \*\//)[number - 1];
4 | };
5 |
--------------------------------------------------------------------------------
/test/cases/js-hash/style.css:
--------------------------------------------------------------------------------
1 | .a {
2 | background: red;
3 | }
4 | /* break */
5 | .a {
6 | background: green;
7 | }
8 |
--------------------------------------------------------------------------------
/test/cases/js-hash/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = [1, 2].map((n) => {
4 | return {
5 | entry: './index.js',
6 | module: {
7 | rules: [
8 | {
9 | test: /\.css$/,
10 | use: [
11 | {
12 | loader: Self.loader,
13 | options: {
14 | hmr: false,
15 | },
16 | },
17 | {
18 | loader: 'css-loader',
19 | options: {
20 | modules: true,
21 | },
22 | },
23 | {
24 | loader: './loader',
25 | ident: 'my-loader',
26 | options: {
27 | number: n,
28 | },
29 | },
30 | ],
31 | },
32 | ],
33 | },
34 | output: {
35 | filename: `[name].[contenthash].${n}.js`,
36 | },
37 | plugins: [
38 | new Self({
39 | filename: `[name].[contenthash].${n}.css`,
40 | }),
41 | ],
42 | };
43 | });
44 |
--------------------------------------------------------------------------------
/test/cases/moduleFilename/expected/demo/css/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: purple;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/moduleFilename/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/moduleFilename/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: purple;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/moduleFilename/webpack.config.js:
--------------------------------------------------------------------------------
1 | const Self = require('../../../');
2 |
3 | module.exports = {
4 | entry: {
5 | 'demo/js/main': './index.js',
6 | },
7 | module: {
8 | rules: [
9 | {
10 | test: /\.css$/,
11 | use: [Self.loader, 'css-loader'],
12 | },
13 | ],
14 | },
15 | output: {
16 | filename: '[name].js',
17 | },
18 | plugins: [
19 | new Self({
20 | moduleFilename: ({ name }) => `${name.replace('/js/', '/css/')}.css`,
21 | }),
22 | ],
23 | };
24 |
--------------------------------------------------------------------------------
/test/cases/moduleFilenameMutableFilename/expected/mutated.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: palegreen;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/moduleFilenameMutableFilename/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/moduleFilenameMutableFilename/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: palegreen;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/moduleFilenameMutableFilename/webpack.config.js:
--------------------------------------------------------------------------------
1 | const Self = require('../../../');
2 |
3 | module.exports = {
4 | entry: {
5 | main: './index.js',
6 | },
7 | module: {
8 | rules: [
9 | {
10 | test: /\.css$/,
11 | use: [Self.loader, 'css-loader'],
12 | },
13 | ],
14 | },
15 | output: {
16 | filename: '[name].js',
17 | },
18 | plugins: [
19 | (() => {
20 | const self = new Self({ filename: 'constructed.css' });
21 |
22 | self.options.filename = 'mutated.css';
23 |
24 | return self;
25 | })(),
26 | ],
27 | };
28 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/a.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/async-one.js:
--------------------------------------------------------------------------------
1 | import './c.css';
2 | import './d.css';
3 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/async-two.js:
--------------------------------------------------------------------------------
1 | import './d.css';
2 | import './c.css';
3 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/b.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/c.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: blue;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/d.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: yellow;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/expected/async-one.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: blue;
3 | }
4 |
5 | body {
6 | background: yellow;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/expected/async-two.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: yellow;
3 | }
4 |
5 | body {
6 | background: blue;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/expected/main-one.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 | body {
6 | background: green;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/expected/main-two.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | }
4 |
5 | body {
6 | background: red;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/index-one.js:
--------------------------------------------------------------------------------
1 | import './a.css';
2 | import './b.css';
3 |
4 | /* eslint-disable-next-line no-unused-expressions */
5 | import(/* webpackChunkName: 'async-one' */ './async-one');
6 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/index-two.js:
--------------------------------------------------------------------------------
1 | import './b.css';
2 | import './a.css';
3 |
4 | /* eslint-disable-next-line no-unused-expressions */
5 | import(/* webpackChunkName: 'async-two' */ './async-two');
6 |
--------------------------------------------------------------------------------
/test/cases/multiple-entry/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: {
5 | 'main-one': './index-one.js',
6 | 'main-two': './index-two.js',
7 | },
8 | module: {
9 | rules: [
10 | {
11 | test: /\.css$/,
12 | use: [Self.loader, 'css-loader'],
13 | },
14 | ],
15 | },
16 | plugins: [
17 | new Self({
18 | filename: '[name].css',
19 | }),
20 | ],
21 | };
22 |
--------------------------------------------------------------------------------
/test/cases/nested/a.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/nested/b.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/nested/component.css:
--------------------------------------------------------------------------------
1 | .component {
2 | background: blue;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/nested/component.js:
--------------------------------------------------------------------------------
1 | import './component.css';
2 |
--------------------------------------------------------------------------------
/test/cases/nested/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 | .component {
6 | background: blue;
7 | }
8 |
9 | body {
10 | background: green;
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/test/cases/nested/index.js:
--------------------------------------------------------------------------------
1 | import './a.css';
2 | import './component';
3 | import './b.css';
4 |
--------------------------------------------------------------------------------
/test/cases/nested/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/no-source-map/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/no-source-map/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/no-source-map/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/no-source-map/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | // Required to disable source maps in webpack@4
6 | devtool: false,
7 | module: {
8 | rules: [
9 | {
10 | test: /\.css$/,
11 | use: [
12 | {
13 | loader: Self.loader,
14 | },
15 | {
16 | loader: 'css-loader',
17 | options: {
18 | sourceMap: false,
19 | },
20 | },
21 | ],
22 | },
23 | ],
24 | },
25 | plugins: [
26 | new Self({
27 | filename: '[name].css',
28 | }),
29 | ],
30 | };
31 |
--------------------------------------------------------------------------------
/test/cases/publicpath-emptystring/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | background-image: url(c9e192c015437a21dea1faa1d30f4941.svg);
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/test/cases/publicpath-emptystring/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/publicpath-emptystring/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/cases/publicpath-emptystring/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | background-image: url(./react.svg);
4 | }
5 |
--------------------------------------------------------------------------------
/test/cases/publicpath-emptystring/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | {
11 | loader: Self.loader,
12 | options: {
13 | publicPath: '',
14 | },
15 | },
16 | 'css-loader',
17 | ],
18 | },
19 | {
20 | test: /\.(svg|png)$/,
21 | use: [
22 | {
23 | loader: 'file-loader',
24 | options: {
25 | filename: '[name].[ext]',
26 | },
27 | },
28 | ],
29 | },
30 | ],
31 | },
32 | plugins: [
33 | new Self({
34 | filename: '[name].css',
35 | }),
36 | ],
37 | };
38 |
--------------------------------------------------------------------------------
/test/cases/publicpath-function/expected/nested/again/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | background-image: url(../../c9e192c015437a21dea1faa1d30f4941.svg);
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/test/cases/publicpath-function/expected/nested/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | background-image: url(../c9e192c015437a21dea1faa1d30f4941.svg);
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/test/cases/publicpath-function/nested/again/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | background-image: url(../../react.svg);
4 | }
5 |
--------------------------------------------------------------------------------
/test/cases/publicpath-function/nested/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | background-image: url(../react.svg);
4 | }
5 |
--------------------------------------------------------------------------------
/test/cases/publicpath-function/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/cases/publicpath-function/webpack.config.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 |
3 | import Self from '../../../src';
4 |
5 | module.exports = {
6 | entry: {
7 | // Specific CSS entry point, with output to a nested folder
8 | 'nested/style': './nested/style.css',
9 | // Note that relative nesting of output is the same as that of the input
10 | 'nested/again/style': './nested/again/style.css',
11 | },
12 | module: {
13 | rules: [
14 | {
15 | test: /\.css$/,
16 | use: [
17 | {
18 | loader: Self.loader,
19 | options: {
20 | // Compute publicPath relative to the CSS output
21 | publicPath: (resourcePath, context) =>
22 | `${path
23 | .relative(path.dirname(resourcePath), context)
24 | .replace(/\\/g, '/')}/`,
25 | },
26 | },
27 | 'css-loader',
28 | ],
29 | },
30 | {
31 | test: /\.(svg|png)$/,
32 | use: [
33 | {
34 | loader: 'file-loader',
35 | options: {
36 | filename: '[name].[ext]',
37 | },
38 | },
39 | ],
40 | },
41 | ],
42 | },
43 | plugins: [
44 | new Self({
45 | filename: '[name].css',
46 | }),
47 | ],
48 | };
49 |
--------------------------------------------------------------------------------
/test/cases/publicpath-trailing-slash/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | background-image: url(/static/img/c9e192c015437a21dea1faa1d30f4941.svg);
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/test/cases/publicpath-trailing-slash/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/publicpath-trailing-slash/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/cases/publicpath-trailing-slash/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | background-image: url(./react.svg);
4 | }
5 |
--------------------------------------------------------------------------------
/test/cases/publicpath-trailing-slash/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | {
11 | loader: Self.loader,
12 | options: {
13 | publicPath: '/static/img',
14 | },
15 | },
16 | 'css-loader',
17 | ],
18 | },
19 | {
20 | test: /\.(svg|png)$/,
21 | use: [
22 | {
23 | loader: 'file-loader',
24 | options: {
25 | filename: '[name].[ext]',
26 | },
27 | },
28 | ],
29 | },
30 | ],
31 | },
32 | plugins: [
33 | new Self({
34 | filename: '[name].css',
35 | }),
36 | ],
37 | };
38 |
--------------------------------------------------------------------------------
/test/cases/shared-import/a.css:
--------------------------------------------------------------------------------
1 | @import './shared.css';
2 |
3 | .shared {
4 | color: red;
5 | }
6 |
--------------------------------------------------------------------------------
/test/cases/shared-import/b.css:
--------------------------------------------------------------------------------
1 | @import './shared.css';
2 |
3 | .shared {
4 | background-color: red;
5 | }
6 |
--------------------------------------------------------------------------------
/test/cases/shared-import/c.css:
--------------------------------------------------------------------------------
1 | @import './shared.css';
2 |
3 | .shared {
4 | border: 1px solid red;
5 | }
6 |
--------------------------------------------------------------------------------
/test/cases/shared-import/expected/1.css:
--------------------------------------------------------------------------------
1 | .shared {
2 | border: 1px solid red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/shared-import/expected/main.css:
--------------------------------------------------------------------------------
1 | .shared {
2 | color: green;
3 | background-color: green;
4 | border: 1px solid green;
5 | }
6 |
7 | .shared {
8 | color: red;
9 | }
10 |
11 | .shared {
12 | background-color: red;
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/test/cases/shared-import/index.js:
--------------------------------------------------------------------------------
1 | import './a.css';
2 | import './b.css';
3 |
4 | /* eslint-disable-next-line no-unused-expressions */
5 | import('./c.css');
6 |
--------------------------------------------------------------------------------
/test/cases/shared-import/shared.css:
--------------------------------------------------------------------------------
1 | .shared {
2 | color: green;
3 | background-color: green;
4 | border: 1px solid green;
5 | }
6 |
--------------------------------------------------------------------------------
/test/cases/shared-import/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/a.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/async-one.js:
--------------------------------------------------------------------------------
1 | import './c.css';
2 | import './d.css';
3 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/async-two.js:
--------------------------------------------------------------------------------
1 | import './e.css';
2 | import './f.css';
3 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/b.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/c.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: blue;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/d.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: yellow;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/e.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: purple;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/expected/async-one.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: blue;
3 | }
4 |
5 | body {
6 | background: yellow;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/expected/async-two.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: purple;
3 | }
4 |
5 | body {
6 | background: indigo;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 | body {
6 | background: green;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/f.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: indigo;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/index.js:
--------------------------------------------------------------------------------
1 | import './a.css';
2 | import './b.css';
3 |
4 | /* eslint-disable-next-line no-unused-expressions */
5 | import(/* webpackChunkName: 'async-one' */ './async-one');
6 | /* eslint-disable-next-line no-unused-expressions */
7 | import(/* webpackChunkName: 'async-two' */ './async-two');
8 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css-fallback/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: {
5 | main: './index.js',
6 | },
7 | module: {
8 | rules: [
9 | {
10 | test: /\.css$/,
11 | use: [Self.loader, 'css-loader'],
12 | },
13 | ],
14 | },
15 | plugins: [
16 | function Plugin() {
17 | this.hooks.compilation.tap('Test', (compilation) => {
18 | compilation.hooks.beforeChunkAssets.tap('Test', () => {
19 | for (const chunkGroup of compilation.chunkGroups) {
20 | // remove getModuleIndex2 to enforce using fallback
21 | // eslint-disable-next-line no-undefined
22 | chunkGroup.getModuleIndex2 = undefined;
23 | }
24 | });
25 | });
26 | },
27 | new Self({
28 | filename: '[name].css',
29 | }),
30 | ],
31 | };
32 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/a.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/async-one.js:
--------------------------------------------------------------------------------
1 | import './c.css';
2 | import './d.css';
3 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/async-two.js:
--------------------------------------------------------------------------------
1 | import './e.css';
2 | import './f.css';
3 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/b.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/c.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: blue;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/d.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: yellow;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/e.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: purple;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/expected/async-one.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: blue;
3 | }
4 |
5 | body {
6 | background: yellow;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/expected/async-two.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: purple;
3 | }
4 |
5 | body {
6 | background: indigo;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 | body {
6 | background: green;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/f.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: indigo;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/index.js:
--------------------------------------------------------------------------------
1 | import './a.css';
2 | import './b.css';
3 |
4 | /* eslint-disable-next-line no-unused-expressions */
5 | import(/* webpackChunkName: 'async-one' */ './async-one');
6 | /* eslint-disable-next-line no-unused-expressions */
7 | import(/* webpackChunkName: 'async-two' */ './async-two');
8 |
--------------------------------------------------------------------------------
/test/cases/simple-async-load-css/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: {
5 | main: './index.js',
6 | },
7 | module: {
8 | rules: [
9 | {
10 | test: /\.css$/,
11 | use: [Self.loader, 'css-loader'],
12 | },
13 | ],
14 | },
15 | plugins: [
16 | new Self({
17 | filename: '[name].css',
18 | }),
19 | ],
20 | };
21 |
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/async.css:
--------------------------------------------------------------------------------
1 | .async {
2 | background: blue;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/async.js:
--------------------------------------------------------------------------------
1 | import './in-async.css';
2 |
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/expected/1.css:
--------------------------------------------------------------------------------
1 | .in-async {
2 | background: green;
3 | }
4 |
5 |
6 | /*# sourceMappingURL=1.css.map*/
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/expected/1.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///./in-async.css"],"names":[],"mappings":"AAAA;AACA;AACA","file":"1.css","sourcesContent":[".in-async {\n background: green;\n}\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/expected/2.css:
--------------------------------------------------------------------------------
1 | .async {
2 | background: blue;
3 | }
4 |
5 |
6 | /*# sourceMappingURL=2.css.map*/
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/expected/2.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///./async.css"],"names":[],"mappings":"AAAA;AACA;AACA","file":"2.css","sourcesContent":[".async {\n background: blue;\n}\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
6 | /*# sourceMappingURL=main.css.map*/
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/expected/main.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///./main.css"],"names":[],"mappings":"AAAA;AACA;AACA","file":"main.css","sourcesContent":["body {\n background: red;\n}\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/in-async.css:
--------------------------------------------------------------------------------
1 | .in-async {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/index.js:
--------------------------------------------------------------------------------
1 | import './main.css';
2 |
3 | /* eslint-disable-next-line no-unused-expressions */
4 | import('./async');
5 |
6 | /* eslint-disable-next-line no-unused-expressions */
7 | import('./async.css');
8 |
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async-source-map/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | devtool: 'source-map',
6 | module: {
7 | rules: [
8 | {
9 | test: /\.css$/,
10 | use: [Self.loader, 'css-loader'],
11 | },
12 | ],
13 | },
14 | plugins: [
15 | new Self({
16 | filename: '[name].css',
17 | }),
18 | ],
19 | };
20 |
--------------------------------------------------------------------------------
/test/cases/simple-async/async.css:
--------------------------------------------------------------------------------
1 | .async {
2 | background: blue;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async/async.js:
--------------------------------------------------------------------------------
1 | import './in-async.css';
2 |
--------------------------------------------------------------------------------
/test/cases/simple-async/expected/1.css:
--------------------------------------------------------------------------------
1 | .in-async {
2 | background: green;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/simple-async/expected/2.css:
--------------------------------------------------------------------------------
1 | .async {
2 | background: blue;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/simple-async/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/simple-async/in-async.css:
--------------------------------------------------------------------------------
1 | .in-async {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async/index.js:
--------------------------------------------------------------------------------
1 | import './main.css';
2 |
3 | /* eslint-disable-next-line no-unused-expressions */
4 | import('./async');
5 |
6 | /* eslint-disable-next-line no-unused-expressions */
7 | import('./async.css');
8 |
--------------------------------------------------------------------------------
/test/cases/simple-async/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-async/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/simple-commonjs-syntax/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/simple-commonjs-syntax/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/simple-commonjs-syntax/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-commonjs-syntax/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | Self.loader,
11 | {
12 | loader: 'css-loader',
13 | // TODO Uncomment after `css-loader` release the `esModule` option
14 | // options: { esModule: false },
15 | },
16 | ],
17 | },
18 | ],
19 | },
20 | plugins: [
21 | new Self({
22 | filename: '[name].css',
23 | }),
24 | ],
25 | };
26 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-global/expected/main.css:
--------------------------------------------------------------------------------
1 | .a {
2 | background: red;
3 | }
4 |
5 | .foo__style__b {
6 | color: green;
7 | }
8 |
9 | .c {
10 | color: blue;
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-global/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-global/style.css:
--------------------------------------------------------------------------------
1 | .a {
2 | background: red;
3 | }
4 |
5 | :local(.b) {
6 | color: green;
7 | }
8 |
9 | :global(.c) {
10 | color: blue;
11 | }
12 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-global/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | Self.loader,
11 | {
12 | loader: 'css-loader',
13 | options: {
14 | modules: {
15 | mode: 'global',
16 | localIdentName: 'foo__[name]__[local]',
17 | },
18 | },
19 | },
20 | ],
21 | },
22 | ],
23 | },
24 | plugins: [
25 | new Self({
26 | filename: '[name].css',
27 | }),
28 | ],
29 | };
30 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-local/expected/main.css:
--------------------------------------------------------------------------------
1 | .foo__style__a {
2 | background: red;
3 | }
4 |
5 | .foo__style__b {
6 | color: green;
7 | }
8 |
9 | .c {
10 | color: blue;
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-local/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-local/style.css:
--------------------------------------------------------------------------------
1 | .a {
2 | background: red;
3 | }
4 |
5 | :local(.b) {
6 | color: green;
7 | }
8 |
9 | :global(.c) {
10 | color: blue;
11 | }
12 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-local/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | Self.loader,
11 | {
12 | loader: 'css-loader',
13 | options: {
14 | modules: {
15 | mode: 'local',
16 | localIdentName: 'foo__[name]__[local]',
17 | },
18 | },
19 | },
20 | ],
21 | },
22 | ],
23 | },
24 | plugins: [
25 | new Self({
26 | filename: '[name].css',
27 | }),
28 | ],
29 | };
30 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-pure/expected/main.css:
--------------------------------------------------------------------------------
1 | .foo__style__a {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-pure/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-pure/style.css:
--------------------------------------------------------------------------------
1 | .a {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-css-modules-mode-pure/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | Self.loader,
11 | {
12 | loader: 'css-loader',
13 | options: {
14 | modules: {
15 | mode: 'pure',
16 | localIdentName: 'foo__[name]__[local]',
17 | },
18 | },
19 | },
20 | ],
21 | },
22 | ],
23 | },
24 | plugins: [
25 | new Self({
26 | filename: '[name].css',
27 | }),
28 | ],
29 | };
30 |
--------------------------------------------------------------------------------
/test/cases/simple-es-module-syntax/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/simple-es-module-syntax/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/simple-es-module-syntax/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-es-module-syntax/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | Self.loader,
11 | {
12 | loader: 'css-loader',
13 | // TODO Uncomment after `css-loader` release the `esModule` option
14 | // options: { esModule: true },
15 | },
16 | ],
17 | },
18 | ],
19 | },
20 | plugins: [
21 | new Self({
22 | filename: '[name].css',
23 | }),
24 | ],
25 | };
26 |
--------------------------------------------------------------------------------
/test/cases/simple-multiple/a.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-multiple/b.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: green;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple-multiple/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 | body {
6 | background: green;
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/test/cases/simple-multiple/index.js:
--------------------------------------------------------------------------------
1 | import './a.css';
2 | import './b.css';
3 |
--------------------------------------------------------------------------------
/test/cases/simple-multiple/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/simple-publicpath/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | background-image: url(/static/img/c9e192c015437a21dea1faa1d30f4941.svg);
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/test/cases/simple-publicpath/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/simple-publicpath/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/cases/simple-publicpath/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | background-image: url(./react.svg);
4 | }
5 |
--------------------------------------------------------------------------------
/test/cases/simple-publicpath/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [
10 | {
11 | loader: Self.loader,
12 | options: {
13 | publicPath: '/static/img/',
14 | },
15 | },
16 | 'css-loader',
17 | ],
18 | },
19 | {
20 | test: /\.(svg|png)$/,
21 | use: [
22 | {
23 | loader: 'file-loader',
24 | options: {
25 | filename: '[name].[ext]',
26 | },
27 | },
28 | ],
29 | },
30 | ],
31 | },
32 | plugins: [
33 | new Self({
34 | filename: '[name].css',
35 | }),
36 | ],
37 | };
38 |
--------------------------------------------------------------------------------
/test/cases/simple/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/simple/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/simple/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/simple/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | plugins: [
14 | new Self({
15 | filename: '[name].css',
16 | }),
17 | ],
18 | };
19 |
--------------------------------------------------------------------------------
/test/cases/source-map/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
6 | /*# sourceMappingURL=main.css.map*/
--------------------------------------------------------------------------------
/test/cases/source-map/index.js:
--------------------------------------------------------------------------------
1 | import './style.css';
2 |
--------------------------------------------------------------------------------
/test/cases/source-map/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/source-map/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | devtool: 'source-map',
6 | module: {
7 | rules: [
8 | {
9 | test: /\.css$/,
10 | use: [
11 | {
12 | loader: Self.loader,
13 | },
14 | {
15 | loader: 'css-loader',
16 | options: {
17 | sourceMap: true,
18 | },
19 | },
20 | ],
21 | },
22 | ],
23 | },
24 | plugins: [
25 | new Self({
26 | filename: '[name].css',
27 | }),
28 | ],
29 | };
30 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/a.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'a';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/b.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'b';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/c.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'c';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/chunk1.js:
--------------------------------------------------------------------------------
1 | import './c.css';
2 | import './d.css';
3 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/chunk2.js:
--------------------------------------------------------------------------------
1 | import './d.css';
2 | import './h.css';
3 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/d.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'd';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/e1.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e1';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/e2.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'e2';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/entry1.js:
--------------------------------------------------------------------------------
1 | import './a.css';
2 | import './e1.css';
3 | import './e2.css';
4 | import './f.css';
5 |
6 | /* eslint-disable-next-line no-unused-expressions */
7 | import('./chunk1');
8 | /* eslint-disable-next-line no-unused-expressions */
9 | import('./chunk2');
10 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/entry2.js:
--------------------------------------------------------------------------------
1 | import './b.css';
2 | import './e2.css';
3 | import './e1.css';
4 | import './g.css';
5 | import './h.css';
6 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/expected/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'a';
3 | }
4 |
5 | body {
6 | content: 'b';
7 | }
8 |
9 | body {
10 | content: 'c';
11 | }
12 |
13 | body {
14 | content: 'd';
15 | }
16 |
17 | body {
18 | content: 'e1';
19 | }
20 |
21 | body {
22 | content: 'e2';
23 | }
24 |
25 | body {
26 | content: 'f';
27 | }
28 |
29 | body {
30 | content: 'g';
31 | }
32 |
33 | body {
34 | content: 'h';
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/f.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'f';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/g.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'g';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/h.css:
--------------------------------------------------------------------------------
1 | body {
2 | content: 'h';
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks-single/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: {
5 | entry1: './entry1.js',
6 | entry2: './entry2.js',
7 | },
8 | module: {
9 | rules: [
10 | {
11 | test: /\.css$/,
12 | use: [Self.loader, 'css-loader'],
13 | },
14 | ],
15 | },
16 | optimization: {
17 | splitChunks: {
18 | cacheGroups: {
19 | styles: {
20 | name: 'styles',
21 | chunks: 'all',
22 | test: /\.css$/,
23 | enforce: true,
24 | },
25 | },
26 | },
27 | },
28 | plugins: [
29 | new Self({
30 | filename: '[name].css',
31 | }),
32 | ],
33 | };
34 |
--------------------------------------------------------------------------------
/test/cases/split-chunks/expected/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/test/cases/split-chunks/expected/vendors.css:
--------------------------------------------------------------------------------
1 | /* This could be bootstrap.css */
2 | body {
3 | background: green;
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/test/cases/split-chunks/index.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line
2 | import 'bootstrap.css';
3 | import './style.css';
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/split-chunks/webpack.config.js:
--------------------------------------------------------------------------------
1 | import Self from '../../../src';
2 |
3 | module.exports = {
4 | entry: './index.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.css$/,
9 | use: [Self.loader, 'css-loader'],
10 | },
11 | ],
12 | },
13 | optimization: {
14 | splitChunks: {
15 | chunks: 'all',
16 | cacheGroups: {
17 | vendors: {
18 | name: 'vendors',
19 | test: /node_modules/,
20 | enforce: true,
21 | },
22 | },
23 | },
24 | },
25 | plugins: [
26 | new Self({
27 | filename: '[name].css',
28 | }),
29 | ],
30 | };
31 |
--------------------------------------------------------------------------------
/test/cjs.test.js:
--------------------------------------------------------------------------------
1 | import MiniCssExtractPlugin from '../src';
2 | import CJSMiniCssExtractPlugin from '../src/cjs';
3 |
4 | describe('CJS', () => {
5 | it('should exported plugin', () => {
6 | expect(CJSMiniCssExtractPlugin).toEqual(MiniCssExtractPlugin);
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/test/fixtures/simple.css:
--------------------------------------------------------------------------------
1 | .foo {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/fixtures/simple.js:
--------------------------------------------------------------------------------
1 | import './simple.css';
2 |
--------------------------------------------------------------------------------
/test/helpers/compile.js:
--------------------------------------------------------------------------------
1 | export default (compiler) => {
2 | return new Promise((resolve, reject) => {
3 | compiler.run((error, stats) => {
4 | if (error) {
5 | return reject(error);
6 | }
7 |
8 | return resolve(stats);
9 | });
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/test/helpers/getCompiler.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 |
3 | import webpack from 'webpack';
4 | import { createFsFromVolume, Volume } from 'memfs';
5 |
6 | import MiniCssExtractPlugin from '../../src';
7 |
8 | export default (fixture, loaderOptions = {}, config = {}) => {
9 | const fullConfig = {
10 | mode: 'development',
11 | devtool: config.devtool || false,
12 | context: path.resolve(__dirname, '../fixtures'),
13 | entry: path.resolve(__dirname, '../fixtures', fixture),
14 | output: {
15 | path: path.resolve(__dirname, '../outputs'),
16 | filename: '[name].bundle.js',
17 | chunkFilename: '[name].chunk.js',
18 | },
19 | module: {
20 | rules: [
21 | {
22 | test: /\.css$/i,
23 | rules: [
24 | {
25 | loader: MiniCssExtractPlugin.loader,
26 | options: loaderOptions || {},
27 | },
28 | {
29 | loader: 'css-loader',
30 | },
31 | ],
32 | },
33 | ],
34 | },
35 | plugins: [
36 | new MiniCssExtractPlugin({
37 | // Options similar to the same options in webpackOptions.output
38 | // both options are optional
39 | filename: '[name].css',
40 | chunkFilename: '[id].css',
41 | }),
42 | ],
43 | ...config,
44 | };
45 |
46 | const compiler = webpack(fullConfig);
47 |
48 | if (!config.outputFileSystem) {
49 | const outputFileSystem = createFsFromVolume(new Volume());
50 | // Todo remove when we drop webpack@4 support
51 | outputFileSystem.join = path.join.bind(path);
52 |
53 | compiler.outputFileSystem = outputFileSystem;
54 | }
55 |
56 | return compiler;
57 | };
58 |
--------------------------------------------------------------------------------
/test/helpers/index.js:
--------------------------------------------------------------------------------
1 | import compile from './compile';
2 | import getCompiler from './getCompiler';
3 |
4 | export { compile, getCompiler };
5 |
--------------------------------------------------------------------------------
/test/ignoreOrder-option.test.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 |
3 | import webpack from 'webpack';
4 |
5 | describe('IgnoreOrder', () => {
6 | it('should emit warnings', (done) => {
7 | const casesDirectory = path.resolve(__dirname, 'cases');
8 | const directoryForCase = path.resolve(casesDirectory, 'ignoreOrderFalse');
9 | // eslint-disable-next-line import/no-dynamic-require, global-require
10 | const webpackConfig = require(path.resolve(
11 | directoryForCase,
12 | 'webpack.config.js'
13 | ));
14 | const compiler = webpack({
15 | ...webpackConfig,
16 | mode: 'development',
17 | context: directoryForCase,
18 | cache: false,
19 | });
20 | compiler.run((err1, stats) => {
21 | expect(stats.hasWarnings()).toBe(true);
22 | done();
23 | });
24 | });
25 |
26 | it('should not emit warnings', (done) => {
27 | const casesDirectory = path.resolve(__dirname, 'cases');
28 | const directoryForCase = path.resolve(casesDirectory, 'ignoreOrder');
29 | // eslint-disable-next-line import/no-dynamic-require, global-require
30 | const webpackConfig = require(path.resolve(
31 | directoryForCase,
32 | 'webpack.config.js'
33 | ));
34 | const compiler = webpack({
35 | ...webpackConfig,
36 | mode: 'development',
37 | context: directoryForCase,
38 | cache: false,
39 | });
40 | compiler.run((err1, stats) => {
41 | expect(stats.hasWarnings()).toBe(false);
42 | done();
43 | });
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/test/inject-option.test.js:
--------------------------------------------------------------------------------
1 | /* global page, document, getComputedStyle */
2 |
3 | const { setup: setupDevServer } = require('jest-dev-server');
4 |
5 | describe('insert-options', () => {
6 | describe('insert-string', () => {
7 | beforeAll(async () => {
8 | await setupDevServer({
9 | command:
10 | 'webpack-dev-server test/cases/insert-string/src/index.js --config test/cases/insert-string/webpack.config.e2e.js',
11 | port: 5000,
12 | launchTimeout: 10000,
13 | });
14 | await page.goto('http://localhost:5000/');
15 | });
16 | it('style preload was injected into body', async () => {
17 | // preloaded1 + main + inject
18 | await expect(await page.$$eval('[type="text/css"]', links => links.length)).toEqual(3);
19 | // inject
20 | await expect(await page.$$eval('[rel="preload"]', preloads => preloads.length)).toEqual(1);
21 | });
22 |
23 | it('body background style was not set', async () => {
24 | const bodyStyle = await page.evaluate(() =>
25 | getComputedStyle(document.body).getPropertyValue('background-color')
26 | );
27 |
28 | await expect(bodyStyle).toBe('rgb(255, 0, 0)');
29 | });
30 | });
31 |
32 | describe('insert-function', () => {
33 | beforeAll(async () => {
34 | await setupDevServer({
35 | command: `webpack-dev-server test/cases/insert-function/src/index.js --config test/cases/insert-function/webpack.config.e2e.js`,
36 | port: 3001,
37 | launchTimeout: 15000,
38 | });
39 | await page.goto('http://localhost:3001/');
40 | });
41 | it('style preload was injected into body', async () => {
42 | // preloaded1 + main + inject
43 | await expect(await page.$$eval('[type="text/css"]', links => links.length)).toEqual(3);
44 | // inject
45 | await expect(await page.$$eval('[rel="preload"]', preloads => preloads.length)).toEqual(1);
46 | });
47 |
48 | it('body background style was not set', async () => {
49 | await page.waitFor(4000);
50 | const bodyStyle = await page.evaluate(() =>
51 | getComputedStyle(document.body).getPropertyValue('background-color')
52 | );
53 |
54 | await expect(bodyStyle).toBe('rgb(255, 0, 0)');
55 | });
56 | });
57 |
58 | afterAll(() => {
59 | // eslint-disable-next-line
60 | const childProcess = require('child_process').exec;
61 | childProcess(`kill $(lsof -t -i:3001)`);
62 | childProcess(`kill $(lsof -t -i:5000)`);
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/test/manual/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faceyspacey/extract-css-chunks-webpack-plugin/18837c2ddc4175313cfd812698e7fae4ae4a7acc/test/manual/README.md
--------------------------------------------------------------------------------
/test/manual/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | extract-css-chunks-webpack-plugin testcase
7 |
8 |
9 |
21 |
26 |
27 |
28 |
29 |
30 | Initial CSS: Must be green
31 |
32 |
33 |
Hot Module Replacement
34 |
RED
35 |
GREEN
36 |
BLUE
37 |
38 |
39 |
Hot Module Replacement + CSS modules
40 |
RED
41 |
GREEN
42 |
BLUE
43 |
44 |
45 |
Lazy CSS: Must be red, but turn green when .
46 |
But turn orange, when . Additional clicks have no effect.
47 |
Refresh and press buttons in reverse order: This should turn green instead.
48 |
49 |
50 |
Lazy CSS: Turn off the network and .
51 |
An error should have appeared.
52 |
Now if you turn the network back on and click it again, it should turn aqua.
53 |
54 |
55 |
Preloaded CSS: Must be green.
56 |
displays an alert and should turn red.
57 |
58 |
59 |
Preloaded inlined CSS: Must be green.
60 |
displays an alert and should turn red.
61 |
62 |
63 |
CrossOriginLoading Option: Must be red.
64 |
loads chunks with crossorigin attribute and should turn green.
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/test/manual/src/crossorigin.css:
--------------------------------------------------------------------------------
1 | .crossorigin {
2 | background: lightgreen;
3 | }
4 |
--------------------------------------------------------------------------------
/test/manual/src/crossorigin.js:
--------------------------------------------------------------------------------
1 | import './crossorigin.css';
2 |
--------------------------------------------------------------------------------
/test/manual/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 | /* global __webpack_public_path__ */
3 | /* eslint-disable no-console, camelcase, no-global-assign */
4 |
5 | import './initial.css';
6 | import './simple.css';
7 | import classes from './simple.module.css';
8 |
9 | console.log('___CLASSES__');
10 | console.log(classes);
11 |
12 | function replaceClass(originalClass, newClass) {
13 | const nodes = document.querySelectorAll(`.${originalClass}`);
14 |
15 | nodes.forEach((node) => {
16 | const { classList } = node;
17 | classList.remove(originalClass);
18 | classList.add(newClass);
19 | });
20 | }
21 |
22 | Object.keys(classes).forEach((localClass) => {
23 | replaceClass(localClass, classes[localClass]);
24 | });
25 |
26 | const handleError = (err) => {
27 | document.querySelector('.errors').textContent += `\n${err.toString()}`;
28 | console.error(err);
29 | };
30 |
31 | const makeButton = (className, fn, shouldDisable = true) => {
32 | const button = document.querySelector(className);
33 | button.addEventListener('click', () => {
34 | if (shouldDisable) {
35 | button.disabled = true;
36 | }
37 | fn()
38 | .then(() => {
39 | button.disabled = false;
40 | })
41 | .catch(handleError);
42 | });
43 | };
44 |
45 | makeButton('.lazy-button', () => import('./lazy.js'));
46 | makeButton('.lazy-button2', () => import('./lazy2.css'));
47 |
48 | makeButton('.preloaded-button1', () =>
49 | import(/* webpackChunkName: "preloaded1" */ './preloaded1')
50 | );
51 | makeButton('.preloaded-button2', () =>
52 | import(/* webpackChunkName: "preloaded2" */ './preloaded2')
53 | );
54 |
55 | makeButton('.lazy-failure-button', () => import('./lazy-failure.js'), false);
56 |
57 | makeButton('.crossorigin', () => {
58 | const originalPublicPath = __webpack_public_path__;
59 | __webpack_public_path__ = 'http://0.0.0.0:8080/dist/';
60 | const promise = import('./crossorigin').then(() => {
61 | const lastTwoElements = Array.from(document.head.children).slice(-2);
62 | const hasCrossorigin = lastTwoElements.every(
63 | (element) => element.crossOrigin === 'anonymous'
64 | );
65 | if (!hasCrossorigin) {
66 | throw new Error('Chunks miss crossorigin="anonymous" attribute.');
67 | }
68 | });
69 | __webpack_public_path__ = originalPublicPath;
70 | return promise;
71 | });
72 |
--------------------------------------------------------------------------------
/test/manual/src/initial.css:
--------------------------------------------------------------------------------
1 | .initial-css {
2 | background: lightgreen;
3 | }
4 |
--------------------------------------------------------------------------------
/test/manual/src/lazy-failure.css:
--------------------------------------------------------------------------------
1 | .lazy-failure-css {
2 | background: aqua;
3 | }
4 |
--------------------------------------------------------------------------------
/test/manual/src/lazy-failure.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 |
3 | import './lazy-failure.css';
4 |
--------------------------------------------------------------------------------
/test/manual/src/lazy.css:
--------------------------------------------------------------------------------
1 | .lazy-css {
2 | background: lightgreen;
3 | }
4 |
--------------------------------------------------------------------------------
/test/manual/src/lazy.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 |
3 | import './lazy.css';
4 |
--------------------------------------------------------------------------------
/test/manual/src/lazy2.css:
--------------------------------------------------------------------------------
1 | .lazy-css {
2 | background: peru;
3 | }
4 |
--------------------------------------------------------------------------------
/test/manual/src/preloaded1.css:
--------------------------------------------------------------------------------
1 | .preloaded-css1 {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/manual/src/preloaded1.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 | /* eslint-disable no-alert */
3 |
4 | import './preloaded1.css';
5 |
6 | alert('Ok');
7 |
--------------------------------------------------------------------------------
/test/manual/src/preloaded2.css:
--------------------------------------------------------------------------------
1 | .preloaded-css2 {
2 | background: red;
3 | }
4 |
--------------------------------------------------------------------------------
/test/manual/src/preloaded2.js:
--------------------------------------------------------------------------------
1 | /* eslint-env browser */
2 | /* eslint-disable no-alert */
3 |
4 | import './preloaded2.css';
5 |
6 | alert('Ok');
7 |
--------------------------------------------------------------------------------
/test/manual/src/simple.css:
--------------------------------------------------------------------------------
1 | .r {
2 | color: red;
3 | }
4 |
5 | .g {
6 | color: green;
7 | }
8 |
9 | .b {
10 | color: blue;
11 | }
12 |
--------------------------------------------------------------------------------
/test/manual/src/simple.module.css:
--------------------------------------------------------------------------------
1 | .rr {
2 | color: red;
3 | }
4 |
5 | .gg {
6 | color: green;
7 | }
8 |
9 | .bb {
10 | color: blue;
11 | }
12 |
--------------------------------------------------------------------------------
/test/manual/webpack.config.js:
--------------------------------------------------------------------------------
1 | const Self = require('../../');
2 |
3 | const ENABLE_HMR =
4 | typeof process.env.ENABLE_HMR !== 'undefined'
5 | ? Boolean(process.env.ENABLE_HMR)
6 | : false;
7 |
8 | const ENABLE_ES_MODULE =
9 | typeof process.env.ES_MODULE !== 'undefined'
10 | ? Boolean(process.env.ES_MODULE)
11 | : false;
12 |
13 | module.exports = {
14 | mode: 'development',
15 | output: {
16 | chunkFilename: '[contenthash].js',
17 | publicPath: '/dist/',
18 | crossOriginLoading: 'anonymous',
19 | },
20 | module: {
21 | rules: [
22 | {
23 | test: /\.css$/,
24 | exclude: [/\.module\.css$/i],
25 | use: [
26 | {
27 | loader: Self.loader,
28 | options: {
29 | hmr: ENABLE_HMR,
30 | },
31 | },
32 | {
33 | loader: 'css-loader',
34 | options: {
35 | esModule: ENABLE_ES_MODULE,
36 | },
37 | },
38 | ],
39 | },
40 | {
41 | test: /\.module\.css$/i,
42 | use: [
43 | {
44 | loader: Self.loader,
45 | options: {
46 | hmr: ENABLE_HMR,
47 | },
48 | },
49 | {
50 | loader: 'css-loader',
51 | options: {
52 | modules: true,
53 | esModule: ENABLE_ES_MODULE,
54 | },
55 | },
56 | ],
57 | },
58 | ],
59 | },
60 | plugins: [
61 | new Self({
62 | filename: '[name].css',
63 | chunkFilename: '[contenthash].css',
64 | }),
65 | ],
66 | devServer: {
67 | contentBase: __dirname,
68 | headers: {
69 | 'Access-Control-Allow-Origin': '*',
70 | },
71 | },
72 | };
73 |
--------------------------------------------------------------------------------
/test/validate-loader-options.test.js:
--------------------------------------------------------------------------------
1 | import { getCompiler, compile } from './helpers';
2 |
3 | describe('validate options', () => {
4 | const tests = {
5 | publicPath: {
6 | success: ['/public/path/to/'],
7 | failure: [true],
8 | },
9 | esModule: {
10 | success: [true, false],
11 | failure: [1],
12 | },
13 | hmr: {
14 | success: [true, false],
15 | failure: [1],
16 | },
17 | reloadAll: {
18 | success: [true, false],
19 | failure: [1],
20 | },
21 | unknown: {
22 | success: [],
23 | // TODO failed in next release
24 | // failure: [1, true, false, 'test', /test/, [], {}, { foo: 'bar' }],
25 | },
26 | };
27 |
28 | function stringifyValue(value) {
29 | if (
30 | Array.isArray(value) ||
31 | (value && typeof value === 'object' && value.constructor === Object)
32 | ) {
33 | return JSON.stringify(value);
34 | }
35 |
36 | return value;
37 | }
38 |
39 | async function createTestCase(key, value, type) {
40 | it(`should ${
41 | type === 'success' ? 'successfully validate' : 'throw an error on'
42 | } the "${key}" option with "${stringifyValue(value)}" value`, async () => {
43 | const compiler = getCompiler('simple.js', { [key]: value });
44 |
45 | let stats;
46 |
47 | try {
48 | stats = await compile(compiler);
49 | } finally {
50 | if (type === 'success') {
51 | expect(stats.hasErrors()).toBe(false);
52 | } else if (type === 'failure') {
53 | const {
54 | compilation: { errors },
55 | } = stats;
56 |
57 | expect(errors).toHaveLength(1);
58 | expect(() => {
59 | throw new Error(errors[0].error.message);
60 | }).toThrowErrorMatchingSnapshot();
61 | }
62 | }
63 | });
64 | }
65 |
66 | for (const [key, values] of Object.entries(tests)) {
67 | for (const type of Object.keys(values)) {
68 | for (const value of values[type]) {
69 | createTestCase(key, value, type);
70 | }
71 | }
72 | }
73 | });
74 |
--------------------------------------------------------------------------------
/test/validate-plugin-options.test.js:
--------------------------------------------------------------------------------
1 | import ExtractCssChunks from '../src';
2 |
3 | describe('validate options', () => {
4 | const tests = {
5 | filename: {
6 | success: ['[name].css'],
7 | failure: [true],
8 | },
9 | chunkFilename: {
10 | success: ['[id].css'],
11 | failure: [true],
12 | },
13 | moduleFilename: {
14 | success: [({ name }) => `${name.replace('/js/', '/css/')}.css`],
15 | failure: [true],
16 | },
17 | ignoreOrder: {
18 | success: [true, false],
19 | failure: [1],
20 | },
21 | inject: { success: [true, true] },
22 | unknown: {
23 | success: [],
24 | // TODO failed in next release
25 | // failure: [1, true, false, 'test', /test/, [], {}, { foo: 'bar' }],
26 | },
27 | };
28 |
29 | function stringifyValue(value) {
30 | if (
31 | Array.isArray(value) ||
32 | (value && typeof value === 'object' && value.constructor === Object)
33 | ) {
34 | return JSON.stringify(value);
35 | }
36 |
37 | return value;
38 | }
39 |
40 | async function createTestCase(key, value, type) {
41 | it(`should ${
42 | type === 'success' ? 'successfully validate' : 'throw an error on'
43 | } the "${key}" option with "${stringifyValue(value)}" value`, async () => {
44 | let error;
45 |
46 | try {
47 | // eslint-disable-next-line no-new
48 | new ExtractCssChunks({ [key]: value });
49 | } catch (errorFromPlugin) {
50 | if (errorFromPlugin.name !== 'ValidationError') {
51 | throw errorFromPlugin;
52 | }
53 |
54 | error = errorFromPlugin;
55 | } finally {
56 | if (type === 'success') {
57 | expect(error).toBeUndefined();
58 | } else if (type === 'failure') {
59 | expect(() => {
60 | throw error;
61 | }).toThrowErrorMatchingSnapshot();
62 | }
63 | }
64 | });
65 | }
66 |
67 | for (const [key, values] of Object.entries(tests)) {
68 | for (const type of Object.keys(values)) {
69 | for (const value of values[type]) {
70 | createTestCase(key, value, type);
71 | }
72 | }
73 | }
74 | });
75 |
--------------------------------------------------------------------------------