Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Disable Extracting Specified CSS Module from Chunks #432

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
39b36e9
feat: ability to disable extract async modules
lsycxyj Jul 20, 2019
188cf5c
feat: ability to disable extract async modules, lint fix
lsycxyj Jul 20, 2019
4a7a1f6
feat: ability to disable extract async modules, add doc
lsycxyj Jul 20, 2019
399aa9a
feat: ability to disable extract async modules, ci fix
lsycxyj Jul 20, 2019
26646ae
feat: ability to disable extract async modules, order fix
lsycxyj Jul 20, 2019
08b8e52
feat: ability to disable extract async modules, wrong initial chunks fix
lsycxyj Jul 21, 2019
775cc0c
feat: ability to disable extract async modules, add manual test
lsycxyj Jul 21, 2019
f9d7df1
feat: ability to disable extract async modules, update lock file
lsycxyj Jul 21, 2019
c38cc8c
feat: ability to disable extract async modules, add tests for js files
lsycxyj Jul 21, 2019
e2177fd
feat: ability to disable extract modules, wip
lsycxyj Jul 22, 2019
4982afb
feat: ability to disable extract modules, remove duplicated dependencies
lsycxyj Jul 24, 2019
81517cc
feat: ability to disable extract modules, update doc
lsycxyj Jul 24, 2019
5b3fbef
feat: ability to disable extract modules, remove boolean type option
lsycxyj Jul 24, 2019
1da949e
feat: ability to disable extract modules, less code difference
lsycxyj Jul 24, 2019
e59a0e1
feat: ability to disable extract modules, less code difference
lsycxyj Jul 24, 2019
37ce619
Merge remote-tracking branch 'origin/feature/disable_async_20190719' …
lsycxyj Jul 24, 2019
6001569
feat: ability to disable extract modules, less regressions
lsycxyj Jul 26, 2019
b986c54
feat: ability to disable extract modules, ci fix
lsycxyj Jul 26, 2019
fa58310
feat: ability to disable extract modules, ci fix
lsycxyj Jul 26, 2019
5de6572
feat: ability to disable extract modules, replace private property
lsycxyj Jul 27, 2019
5b2c6d3
feat: ability to disable extract modules, remove useless code
lsycxyj Jul 31, 2019
2f29038
merge from master WIP
lsycxyj Feb 3, 2020
f0358d0
fix wrong modules after disable extraction
lsycxyj Feb 4, 2020
cbcfbc5
Merge remote-tracking branch 'upstream/master' into feature/disable_a…
lsycxyj Aug 6, 2020
40af212
fix wrong modification and update package-lock.json
lsycxyj Aug 6, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Expand Up @@ -499,7 +499,22 @@ module.exports = {
};
```

### Module Filename Option
### Disable Extracting Specified CSS from Chunks

You may disable extracting css modules programmatically by passing a function.

```javascript
const miniCssExtractPlugin = new MiniCssExtractPlugin({
disableExtract({ module, isAsync }) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name it in positive way e.g. should extract

// Do whatever you want. Disable by content size for example:
// return module.content.length < 10 * 1024;
// Or disable extracting from all async chunks
return isAsync;
},
});
```

#### Module Filename Option

With the `moduleFilename` option you can use chunk data to customize the filename. This is particularly useful when dealing with multiple entry points and wanting to get more control out of the filename for a given entry point/chunk. In the example below, we'll use `moduleFilename` to output the generated css into a different directory.

Expand Down
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -74,6 +74,7 @@
"npm-run-all": "^4.1.5",
"prettier": "^1.19.1",
"standard-version": "^7.0.1",
"style-loader": "^0.23.1",
"webpack": "^4.41.4",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2"
Expand Down
80 changes: 80 additions & 0 deletions src/index.js
Expand Up @@ -24,6 +24,16 @@ const REGEXP_NAME = /\[name\]/i;
const REGEXP_PLACEHOLDERS = /\[(name|id|chunkhash)\]/g;
const DEFAULT_FILENAME = '[name].css';

function isInitialOrHasNoParents(chunk) {
let parentCount = 0;

for (const chunkGroup of chunk.groupsIterable) {
parentCount += chunkGroup.getNumberOfParents();
}

return chunk.isOnlyInitial() || parentCount === 0;
}

class CssDependencyTemplate {
apply() {}
}
Expand Down Expand Up @@ -129,6 +139,20 @@ class MiniCssExtractPlugin {

apply(compiler) {
compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
let moduleToBeRebuild = new Set();
// eslint-disable-next-line no-param-reassign
compilation[MODULE_TYPE] = {
moduleToBeRebuild,
};

compilation.hooks.normalModuleLoader.tap(pluginName, (lc, m) => {
const loaderContext = lc;
const module = m;
loaderContext[`${MODULE_TYPE}/disableExtract`] = () => {
return !!module[`${MODULE_TYPE}/disableExtract`];
};
});

compilation.dependencyFactories.set(
CssDependency,
new CssModuleFactory()
Expand Down Expand Up @@ -390,9 +414,65 @@ class MiniCssExtractPlugin {
return source;
}
);

compilation.hooks.optimizeTree.tapAsync(
pluginName,
(chunks, modules, callback) => {
const promises = [];

for (const chunk of chunks) {
const isAsync = !isInitialOrHasNoParents(chunk);
for (const module of chunk.modulesIterable) {
if (module.type === MODULE_TYPE) {
if (this.shouldDisableExtract({ module, isAsync })) {
moduleToBeRebuild.add(module);
}
}
}
}

for (const currentModuleToBeRebuild of moduleToBeRebuild) {
const { issuer } = currentModuleToBeRebuild;
if (!issuer[`${MODULE_TYPE}/disableExtract`]) {
issuer[`${MODULE_TYPE}/disableExtract`] = true;
promises.push(
new Promise((resolve) => {
compilation.rebuildModule(issuer, (err) => {
if (err) {
compilation.errors.push(err);
}
resolve();
});
})
);
}
}

Promise.all(promises).then(() => callback());
}
);

// Trigger seal again if there are modules to be rebuilt
compilation.hooks.needAdditionalSeal.tap(pluginName, () => {
if (moduleToBeRebuild.size > 0) {
moduleToBeRebuild = new Set();
return true;
}
return false;
});
});
}

shouldDisableExtract({ module, isAsync }) {
const { disableExtract } = this.options;
let shouldDisable = false;
if (typeof disableExtract === 'function') {
shouldDisable = disableExtract({ module, isAsync });
}

return shouldDisable;
}

getCssChunkObject(mainChunk) {
const obj = {};

Expand Down
9 changes: 8 additions & 1 deletion src/loader.js
Expand Up @@ -14,6 +14,7 @@ import CssDependency from './CssDependency';

import schema from './loader-options.json';

const MODULE_TYPE = 'css/mini-extract';
const pluginName = 'mini-css-extract-plugin';

function hotLoader(content, context) {
Expand Down Expand Up @@ -66,6 +67,10 @@ export function pitch(request) {

this.addDependency(this.resourcePath);

if (this[`${MODULE_TYPE}/disableExtract`]()) {
return;
}

const childFilename = '*';
const publicPath =
typeof options.publicPath === 'string'
Expand Down Expand Up @@ -223,4 +228,6 @@ export function pitch(request) {
});
}

export default function() {}
export default function(source) {
return source;
}
3 changes: 3 additions & 0 deletions test/cases/disable-extract-func/async-import.css
@@ -0,0 +1,3 @@
.async-import {
background: black;
}
3 changes: 3 additions & 0 deletions test/cases/disable-extract-func/async.css
@@ -0,0 +1,3 @@
.async {
background: blue;
}
9 changes: 9 additions & 0 deletions test/cases/disable-extract-func/async.js
@@ -0,0 +1,9 @@
import './in-async';
import './in-async2.css';
import './in-async.css';
import './both-async.css';

import './both-page-async-disabled.css';
import './both-page-async.css';

// console.log('async.js');
5 changes: 5 additions & 0 deletions test/cases/disable-extract-func/async2.js
@@ -0,0 +1,5 @@
import './both-page-async-disabled.css';
import './both-page-async.css';
import './is-async1.css';

// console.log('async2.js');
5 changes: 5 additions & 0 deletions test/cases/disable-extract-func/both-async.css
@@ -0,0 +1,5 @@
@import 'shared.css';

.both-async {
color: red;
}
3 changes: 3 additions & 0 deletions test/cases/disable-extract-func/both-page-async-disabled.css
@@ -0,0 +1,3 @@
.both-page-async-disabled {
color: yellow;
}
3 changes: 3 additions & 0 deletions test/cases/disable-extract-func/both-page-async.css
@@ -0,0 +1,3 @@
.both-page-async {
color: cyan;
}
12 changes: 12 additions & 0 deletions test/cases/disable-extract-func/expected/1.css
@@ -0,0 +1,12 @@
.async-import {
background: black;
}

.in-async-2 {
background: green;
}

.both-page-async {
color: cyan;
}