mini-css-extract-plugin
Advanced tools
Comparing version
@@ -5,2 +5,16 @@ # Change Log | ||
<a name="0.4.1"></a> | ||
## [0.4.1](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v0.4.0...v0.4.1) (2018-06-29) | ||
### Bug Fixes | ||
* CSS ordering with multiple entry points ([#130](https://github.com/webpack-contrib/mini-css-extract-plugin/issues/130)) ([79373eb](https://github.com/webpack-contrib/mini-css-extract-plugin/commit/79373eb)) | ||
# Change Log | ||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. | ||
x.x.x / <year>-<month>-<day> | ||
@@ -7,0 +21,0 @@ ================== |
@@ -160,3 +160,3 @@ 'use strict'; | ||
result.push({ | ||
render: () => this.renderContentAsset(renderedModules, compilation.runtimeTemplate.requestShortener), | ||
render: () => this.renderContentAsset(chunk, renderedModules, compilation.runtimeTemplate.requestShortener), | ||
filenameTemplate: this.options.filename, | ||
@@ -167,3 +167,3 @@ pathOptions: { | ||
}, | ||
identifier: `mini-css-extract-plugin.${chunk.id}`, | ||
identifier: `${pluginName}.${chunk.id}`, | ||
hash: chunk.contentHash[NS] | ||
@@ -177,3 +177,3 @@ }); | ||
result.push({ | ||
render: () => this.renderContentAsset(renderedModules, compilation.runtimeTemplate.requestShortener), | ||
render: () => this.renderContentAsset(chunk, renderedModules, compilation.runtimeTemplate.requestShortener), | ||
filenameTemplate: this.options.chunkFilename, | ||
@@ -184,3 +184,3 @@ pathOptions: { | ||
}, | ||
identifier: `mini-css-extract-plugin.${chunk.id}`, | ||
identifier: `${pluginName}.${chunk.id}`, | ||
hash: chunk.contentHash[NS] | ||
@@ -260,3 +260,3 @@ }); | ||
}); | ||
return Template.asString([source, '', '// mini-css-extract-plugin CSS loading', `var cssChunks = ${JSON.stringify(chunkMap)};`, 'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);', 'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {', Template.indent(['promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {', Template.indent([`var href = ${linkHrefPath};`, `var fullhref = ${mainTemplate.requireFn}.p + href;`, 'var existingLinkTags = document.getElementsByTagName("link");', 'for(var i = 0; i < existingLinkTags.length; i++) {', Template.indent(['var tag = existingLinkTags[i];', 'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");', 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();']), '}', 'var existingStyleTags = document.getElementsByTagName("style");', 'for(var i = 0; i < existingStyleTags.length; i++) {', Template.indent(['var tag = existingStyleTags[i];', 'var dataHref = tag.getAttribute("data-href");', 'if(dataHref === href || dataHref === fullhref) return resolve();']), '}', 'var linkTag = document.createElement("link");', 'linkTag.rel = "stylesheet";', 'linkTag.type = "text/css";', 'linkTag.onload = resolve;', 'linkTag.onerror = function(event) {', Template.indent(['var request = event && event.target && event.target.src || fullhref;', 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");', 'err.request = request;', 'reject(err);']), '};', 'linkTag.href = fullhref;', 'var head = document.getElementsByTagName("head")[0];', 'head.appendChild(linkTag);']), '}).then(function() {', Template.indent(['installedCssChunks[chunkId] = 0;']), '}));']), '}']); | ||
return Template.asString([source, '', `// ${pluginName} CSS loading`, `var cssChunks = ${JSON.stringify(chunkMap)};`, 'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);', 'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {', Template.indent(['promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {', Template.indent([`var href = ${linkHrefPath};`, `var fullhref = ${mainTemplate.requireFn}.p + href;`, 'var existingLinkTags = document.getElementsByTagName("link");', 'for(var i = 0; i < existingLinkTags.length; i++) {', Template.indent(['var tag = existingLinkTags[i];', 'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");', 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();']), '}', 'var existingStyleTags = document.getElementsByTagName("style");', 'for(var i = 0; i < existingStyleTags.length; i++) {', Template.indent(['var tag = existingStyleTags[i];', 'var dataHref = tag.getAttribute("data-href");', 'if(dataHref === href || dataHref === fullhref) return resolve();']), '}', 'var linkTag = document.createElement("link");', 'linkTag.rel = "stylesheet";', 'linkTag.type = "text/css";', 'linkTag.onload = resolve;', 'linkTag.onerror = function(event) {', Template.indent(['var request = event && event.target && event.target.src || fullhref;', 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");', 'err.request = request;', 'reject(err);']), '};', 'linkTag.href = fullhref;', 'var head = document.getElementsByTagName("head")[0];', 'head.appendChild(linkTag);']), '}).then(function() {', Template.indent(['installedCssChunks[chunkId] = 0;']), '}));']), '}']); | ||
} | ||
@@ -281,4 +281,18 @@ return source; | ||
renderContentAsset(modules, requestShortener) { | ||
modules.sort((a, b) => a.index2 - b.index2); | ||
renderContentAsset(chunk, modules, requestShortener) { | ||
// get first chunk group and take ordr from this one | ||
// When a chunk is shared between multiple chunk groups | ||
// with different order this can lead to wrong order | ||
// but it's not possible to create a correct order in | ||
// this case. Don't share chunks if you don't like it. | ||
const [chunkGroup] = chunk.groupsIterable; | ||
if (typeof chunkGroup.getModuleIndex2 === 'function') { | ||
modules.sort((a, b) => chunkGroup.getModuleIndex2(a) - chunkGroup.getModuleIndex2(b)); | ||
} else { | ||
// fallback for older webpack versions | ||
// (to avoid a breaking change) | ||
// TODO remove this in next mayor version | ||
// and increase minimum webpack version to 4.12.0 | ||
modules.sort((a, b) => a.index2 - b.index2); | ||
} | ||
const source = new ConcatSource(); | ||
@@ -285,0 +299,0 @@ const externalsSource = new ConcatSource(); |
@@ -49,2 +49,3 @@ 'use strict'; | ||
const NS = _path2.default.dirname(_fs2.default.realpathSync(__filename)); | ||
const pluginName = 'mini-css-extract-plugin'; | ||
@@ -78,12 +79,12 @@ const exec = (loaderContext, code, filename) => { | ||
}; | ||
const childCompiler = this._compilation.createChildCompiler(`mini-css-extract-plugin ${request}`, outputOptions); | ||
const childCompiler = this._compilation.createChildCompiler(`${pluginName} ${request}`, outputOptions); | ||
new _NodeTemplatePlugin2.default(outputOptions).apply(childCompiler); | ||
new _LibraryTemplatePlugin2.default(null, 'commonjs2').apply(childCompiler); | ||
new _NodeTargetPlugin2.default().apply(childCompiler); | ||
new _SingleEntryPlugin2.default(this.context, `!!${request}`, 'mini-css-extract-plugin').apply(childCompiler); | ||
new _SingleEntryPlugin2.default(this.context, `!!${request}`, pluginName).apply(childCompiler); | ||
new _LimitChunkCountPlugin2.default({ maxChunks: 1 }).apply(childCompiler); | ||
// We set loaderContext[NS] = false to indicate we already in | ||
// a child compiler so we don't spawn another child compilers from there. | ||
childCompiler.hooks.thisCompilation.tap('mini-css-extract-plugin loader', compilation => { | ||
compilation.hooks.normalModuleLoader.tap('mini-css-extract-plugin loader', (loaderContext, module) => { | ||
childCompiler.hooks.thisCompilation.tap(`${pluginName} loader`, compilation => { | ||
compilation.hooks.normalModuleLoader.tap(`${pluginName} loader`, (loaderContext, module) => { | ||
loaderContext[NS] = false; // eslint-disable-line no-param-reassign | ||
@@ -104,3 +105,3 @@ if (module.request === request) { | ||
let source; | ||
childCompiler.hooks.afterCompile.tap('mini-css-extract-plugin', compilation => { | ||
childCompiler.hooks.afterCompile.tap(pluginName, compilation => { | ||
source = compilation.assets[childFilename] && compilation.assets[childFilename].source(); | ||
@@ -154,3 +155,3 @@ | ||
} | ||
let resultSource = '// extracted by mini-css-extract-plugin'; | ||
let resultSource = `// extracted by ${pluginName}`; | ||
if (locals && typeof resultSource !== 'undefined') { | ||
@@ -157,0 +158,0 @@ resultSource += `\nmodule.exports = ${JSON.stringify(locals)};`; |
{ | ||
"name": "mini-css-extract-plugin", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"description": "desc", | ||
"license": "MIT", | ||
"repository": "webpack-contrib/mini-css-extract-plugin", | ||
"author": "Tobias Koppers @sokra", | ||
"homepage": "https://github.com/webpack-contrib/mini-css-extract-plugin", | ||
"bugs": "https://github.com/webpack-contrib/mini-css-extract-plugin/issues", | ||
"bin": "", | ||
"main": "dist/cjs.js", | ||
"repository": "https://github.com/webpack-contrib/mini-css-extract-plugin", | ||
"author": "Tobias Koppers @sokra", | ||
"license": "MIT", | ||
"private": false, | ||
"engines": { | ||
"node": ">= 6.9.0 <7.0.0 || >= 8.9.0" | ||
}, | ||
"scripts": { | ||
"webpack-defaults": "webpack-defaults", | ||
"start": "npm run build -- -w", | ||
"appveyor:test": "npm run test", | ||
"build": "cross-env NODE_ENV=production babel src -d dist --ignore 'src/**/*.test.js'", | ||
"build": "cross-env NODE_ENV=production babel src -d dist --ignore 'src/**/*.test.js' --copy-files", | ||
"clean": "del-cli dist", | ||
"commitlint": "commitlint", | ||
"commitmsg": "commitlint -e $GIT_PARAMS", | ||
"lint": "eslint --cache src test", | ||
"ci:lint:commits": "commitlint --from=${CIRCLE_BRANCH} --to=${CIRCLE_SHA1}", | ||
"lint-staged": "lint-staged", | ||
@@ -21,2 +27,4 @@ "prebuild": "npm run clean", | ||
"release": "standard-version", | ||
"release:ci": "conventional-github-releaser -p angular", | ||
"release:validate": "commitlint --from=$(git describe --tags --abbrev=0) --to=$(git rev-parse HEAD)", | ||
"security": "nsp check", | ||
@@ -27,7 +35,22 @@ "test": "jest", | ||
"test:manual": "webpack-dev-server test/manual/src/index.js --open --config test/manual/webpack.config.js", | ||
"travis:lint": "npm run lint && npm run security", | ||
"travis:test": "npm run test -- --runInBand", | ||
"travis:coverage": "npm run test:coverage -- --runInBand" | ||
"ci:lint": "npm run lint && npm run security", | ||
"ci:test": "npm run test -- --runInBand", | ||
"ci:coverage": "npm run test:coverage -- --runInBand", | ||
"defaults": "webpack-defaults" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"peerDependencies": { | ||
"webpack": "^4.4.0" | ||
}, | ||
"dependencies": { | ||
"@webpack-contrib/schema-utils": "^1.0.0-beta.0", | ||
"loader-utils": "^1.1.0", | ||
"webpack-sources": "^1.1.0" | ||
}, | ||
"devDependencies": { | ||
"@commitlint/cli": "^6.1.3", | ||
"@commitlint/config-conventional": "^6.1.3", | ||
"@webpack-contrib/eslint-config-webpack": "^2.0.4", | ||
"babel-cli": "^6.26.0", | ||
@@ -38,27 +61,27 @@ "babel-jest": "^22.2.2", | ||
"babel-preset-env": "^1.6.1", | ||
"conventional-github-releaser": "^2.0.2", | ||
"cross-env": "^5.1.3", | ||
"css-loader": "^0.28.10", | ||
"del": "^3.0.0", | ||
"del-cli": "^1.1.0", | ||
"eslint": "^4.17.0", | ||
"eslint-config-webpack": "^1.2.5", | ||
"eslint-plugin-import": "^2.8.0", | ||
"eslint-plugin-prettier": "^2.6.0", | ||
"file-loader": "^1.1.11", | ||
"husky": "^0.14.3", | ||
"jest": "^22.2.2", | ||
"lint-staged": "^6.1.0", | ||
"memory-fs": "^0.4.1", | ||
"nsp": "^3.1.0", | ||
"pre-commit": "^1.2.2", | ||
"prettier": "^1.11.1", | ||
"standard-version": "^4.3.0", | ||
"webpack": "^4.4.0", | ||
"webpack": "^4.14.0", | ||
"webpack-cli": "^2.0.13", | ||
"webpack-defaults": "^1.6.0", | ||
"webpack-defaults": "^2.3.0", | ||
"webpack-dev-server": "^3.1.1" | ||
}, | ||
"files": [ | ||
"dist" | ||
"keywords": [ | ||
"webpack" | ||
], | ||
"engines": { | ||
"node": ">= 6.11.5" | ||
}, | ||
"peerDependencies": { | ||
"webpack": "^4.4.0" | ||
}, | ||
"pre-commit": "lint-staged", | ||
@@ -70,7 +93,3 @@ "lint-staged": { | ||
] | ||
}, | ||
"dependencies": { | ||
"loader-utils": "^1.1.0", | ||
"webpack-sources": "^1.1.0" | ||
} | ||
} |
147
README.md
@@ -1,7 +0,1 @@ | ||
[![npm][npm]][npm-url] | ||
[![deps][deps]][deps-url] | ||
[![test][test]][test-url] | ||
[![coverage][cover]][cover-url] | ||
[![chat][chat]][chat-url] | ||
<div align="center"> | ||
@@ -14,7 +8,12 @@ <!-- replace with accurate logo e.g from https://worldvectorlogo.com/ --> | ||
<h1>mini-css-extract-plugin</h1> | ||
<p>desc</p> | ||
</div> | ||
This plugin extract CSS into separate files. It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps. | ||
[![npm][npm]][npm-url] | ||
[![deps][deps]][deps-url] | ||
[![tests][tests]][tests-url] | ||
[![coverage][cover]][cover-url] | ||
[![chat][chat]][chat-url] | ||
This plugin extracts CSS into separate files. It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps. | ||
It builds on top of a new webpack v4 feature (module types) and requires webpack 4 to work. | ||
@@ -43,2 +42,4 @@ | ||
#### Minimal example | ||
**webpack.config.js** | ||
@@ -62,3 +63,10 @@ | ||
use: [ | ||
MiniCssExtractPlugin.loader, | ||
{ | ||
loader: MiniCssExtractPlugin.loader, | ||
options: { | ||
// you can specify a publicPath here | ||
// by default it use publicPath in webpackOptions.output | ||
publicPath: '../' | ||
} | ||
}, | ||
"css-loader" | ||
@@ -72,2 +80,42 @@ ] | ||
#### Advanced configuration example | ||
This plugin should be used only on `production` builds without `style-loader` in the loaders chain, especially if you want to have HMR in `development`. | ||
Here is an example to have both HMR in `development` and your styles extracted in a file for `production` builds. | ||
(Loaders options left out for clarity, adapt accordingly to your needs.) | ||
**webpack.config.js** | ||
```js | ||
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); | ||
const devMode = process.env.NODE_ENV !== 'production' | ||
module.exports = { | ||
plugins: [ | ||
new MiniCssExtractPlugin({ | ||
// Options similar to the same options in webpackOptions.output | ||
// both options are optional | ||
filename: devMode ? '[name].css' : '[name].[hash].css', | ||
chunkFilename: devMode ? '[id].css' : '[id].[hash].css', | ||
}) | ||
], | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.(sa|sc|c)ss$/, | ||
use: [ | ||
devMode ? 'style-loader' : MiniCssExtractPlugin.loader, | ||
'css-loader', | ||
'postcss-loader', | ||
'sass-loader', | ||
], | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
### Minimizing For Production | ||
@@ -165,2 +213,64 @@ | ||
#### Extracting CSS based on entry | ||
You may also extract the CSS based on the webpack entry name. This is especially useful if you import routes dynamically | ||
but want to keep your CSS bundled according to entry. This also prevents the CSS duplication issue one had with the | ||
ExtractTextPlugin. | ||
```javascript | ||
const path = require('path'); | ||
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); | ||
function recursiveIssuer(m) { | ||
if (m.issuer) { | ||
return recursiveIssuer(m.issuer); | ||
} else if (m.name) { | ||
return m.name; | ||
} else { | ||
return false; | ||
} | ||
} | ||
module.exports = { | ||
entry: { | ||
foo: path.resolve(__dirname, 'src/foo'), | ||
bar: path.resolve(__dirname, 'src/bar') | ||
}, | ||
optimization: { | ||
splitChunks: { | ||
cacheGroups: { | ||
fooStyles: { | ||
name: 'foo', | ||
test: (m,c,entry = 'foo') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry, | ||
chunks: 'all', | ||
enforce: true | ||
}, | ||
barStyles: { | ||
name: 'bar', | ||
test: (m,c,entry = 'bar') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry, | ||
chunks: 'all', | ||
enforce: true | ||
} | ||
} | ||
} | ||
}, | ||
plugins: [ | ||
new MiniCssExtractPlugin({ | ||
filename: "[name].css", | ||
}) | ||
], | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.css$/, | ||
use: [ | ||
MiniCssExtractPlugin.loader, | ||
"css-loader" | ||
] | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
<h2 align="center">Maintainers</h2> | ||
@@ -187,15 +297,22 @@ | ||
[npm]: https://img.shields.io/npm/v/mini-css-extract-plugin.svg | ||
## License | ||
#### [MIT](./LICENSE) | ||
[npm]: https://img.shields.io/npm/v/webpack-contrib/mini-css-extract-plugin.svg | ||
[npm-url]: https://npmjs.com/package/mini-css-extract-plugin | ||
[node]: https://img.shields.io/node/v/webpack-contrib/mini-css-extract-plugin.svg | ||
[node-url]: https://nodejs.org | ||
[deps]: https://david-dm.org/webpack-contrib/mini-css-extract-plugin.svg | ||
[deps-url]: https://david-dm.org/webpack-contrib/mini-css-extract-plugin | ||
[chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg | ||
[chat-url]: https://gitter.im/webpack/webpack | ||
[tests]: https://img.shields.io/circleci/project/github/webpack-contrib/mini-css-extract-plugin.svg | ||
[tests-url]: https://circleci.com/gh/webpack-contrib/mini-css-extract-plugin | ||
[test]: http://img.shields.io/travis/webpack-contrib/mini-css-extract-plugin.svg | ||
[test-url]: https://travis-ci.org/webpack-contrib/mini-css-extract-plugin | ||
[cover]: https://codecov.io/gh/webpack-contrib/mini-css-extract-plugin/branch/master/graph/badge.svg | ||
[cover-url]: https://codecov.io/gh/webpack-contrib/mini-css-extract-plugin | ||
[chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg | ||
[chat-url]: https://gitter.im/webpack/webpack |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
31921
18.62%428
3.63%1
-50%313
59.69%4
33.33%29
45%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added