|
1 | 1 | [![npm][npm]][npm-url]
|
2 |
| -[![node][node]][node-url] |
3 |
| -[![deps][deps]][deps-url] |
4 |
| -[![tests][tests]][tests-url] |
5 |
| -[![coverage][cover]][cover-url] |
6 | 2 | [![chat][chat]][chat-url]
|
7 | 3 |
|
8 |
| -<div align="center"> |
9 |
| - <img width="200" height="200" |
10 |
| - src="https://cdn.rawgit.com/webpack-contrib/extract-text-webpack-plugin/574e3200/logo.svg"> |
11 |
| - <a href="https://github.com/webpack/webpack"> |
12 |
| - <img width="200" height="200" |
13 |
| - src="https://webpack.js.org/assets/icon-square-big.svg"> |
14 |
| - </a> |
15 |
| - <h1>Extract Text Plugin</h1> |
16 |
| -</div> |
| 4 | +# Extract CSS Chunk |
17 | 5 |
|
18 |
| -<h2 align="center">Install</h2> |
| 6 | +Like the Extract Text Webpack Plugin, but creates multiple css files (one per chunk). Then, as part of server side rendering, you can deliver just the css chunks needed by the current request. |
19 | 7 |
|
20 |
| -```bash |
21 |
| -# for webpack 2 |
22 |
| -npm install --save-dev extract-text-webpack-plugin |
23 |
| -# for webpack 1 |
24 |
| -npm install --save-dev extract-text-webpack-plugin@1.0.1 |
25 |
| -``` |
| 8 | +In addition, for each javascript chunk created another js chunk is created with the styles injected via style-loader |
| 9 | +so that when the client asynchronously loads more chunks the styles will be available as well. This is as opposed to to the chunks you |
| 10 | +initially serve embedded in the page, which are post-fixed with `no_css.js`, which do not inject styles since it's expected that |
| 11 | +the corresponding extracted CSS files are embedded in the page as well. This obviously serves the purpose of reducing the size of your initially |
| 12 | +served javascript chunks. As much as possible has been thought of to make this a complete solution. |
| 13 | + |
| 14 | +BONUS: It also has first-class support for Hot Module Replacement across those css files/chunks. |
26 | 15 |
|
27 |
| -<h2 align="center">Usage</h2> |
| 16 | +NOTE: most the code comes from the original Extract Text Webpack Plugin--the goal is to merge this functionality back into that package at some point. That might be a while. Until then I'd feel totally comfortable just using this package. It's meant specifically for use with *React Loadable*. For complete usage, see the [React Loadable Example](https://github.com/thejameskyle/react-loadable-example). |
28 | 17 |
|
29 |
| -> :warning: For webpack v1, see [the README in the webpack-1 branch](https://github.com/webpack/extract-text-webpack-plugin/blob/webpack-1/README.md). |
| 18 | +## Install |
| 19 | +```bash |
| 20 | +yarn add --dev extract-css-chunk |
| 21 | +``` |
30 | 22 |
|
| 23 | +## Usage |
31 | 24 | ```js
|
32 |
| -const ExtractTextPlugin = require("extract-text-webpack-plugin"); |
| 25 | +const ExtractCssChunk = require("extract-css-chunk") |
33 | 26 |
|
34 | 27 | module.exports = {
|
35 | 28 | module: {
|
36 | 29 | rules: [
|
37 | 30 | {
|
38 | 31 | test: /\.css$/,
|
39 |
| - use: ExtractTextPlugin.extract({ |
40 |
| - fallback: "style-loader", |
41 |
| - use: "css-loader" |
| 32 | + use: ExtractCssChunk.extract({ |
| 33 | + use: 'css-loader?modules&localIdentName=[name]__[local]--[hash:base64:5]', |
42 | 34 | })
|
43 | 35 | }
|
44 | 36 | ]
|
45 | 37 | },
|
46 | 38 | plugins: [
|
47 |
| - new ExtractTextPlugin("styles.css"), |
| 39 | + new ExtractCssChunk, |
48 | 40 | ]
|
49 | 41 | }
|
50 | 42 | ```
|
51 | 43 |
|
52 |
| -It moves all the `require("style.css")`s in entry chunks into a separate single CSS file. So your styles are no longer inlined into the JS bundle, but separate in a CSS bundle file (`styles.css`). If your total stylesheet volume is big, it will be faster because the CSS bundle is loaded in parallel to the JS bundle. |
53 |
| - |
54 |
| -|Advantages|Caveats| |
55 |
| -|:---------|:------| |
56 |
| -| Fewer style tags (older IE has a limit) | Additional HTTP request | |
57 |
| -| CSS SourceMap (with `devtool: "source-map"` and `extract-text-webpack-plugin?sourceMap`) | Longer compilation time | |
58 |
| -| CSS requested in parallel | No runtime public path modification | |
59 |
| -| CSS cached separate | No Hot Module Replacement | |
60 |
| -| Faster runtime (less code and DOM operations) | ... | |
61 |
| - |
62 |
| -<h2 align="center">Options</h2> |
63 |
| - |
64 |
| -```js |
65 |
| -new ExtractTextPlugin(options: filename | object) |
66 |
| -``` |
67 |
| - |
68 |
| -|Name|Type|Description| |
69 |
| -|:--:|:--:|:----------| |
70 |
| -|**`id`**|`{String}`|Unique ident for this plugin instance. (For advanced usage only, by default automatically generated)| |
71 |
| -|**`filename`**|`{String|Function}`|Name of the result file. May contain `[name]`, `[id]` and `[contenthash]`| |
72 |
| -|**`allChunks`**|`{Boolean}`|Extract from all additional chunks too (by default it extracts only from the initial chunk(s))| |
73 |
| -|**`disable`**|`{Boolean}`|Disables the plugin| |
74 |
| -|**`ignoreOrder`**|`{Boolean}`|Disables order check (useful for CSS Modules!), `false` by default| |
75 |
| - |
76 |
| -* `[name]` name of the chunk |
77 |
| -* `[id]` number of the chunk |
78 |
| -* `[contenthash]` hash of the content of the extracted file |
79 |
| - |
80 |
| -> :warning: `ExtractTextPlugin` generates a file **per entry**, so you must use `[name]`, `[id]` or `[contenthash]` when using multiple entries. |
81 |
| -
|
82 |
| -#### `#extract` |
83 |
| - |
84 |
| -```js |
85 |
| -ExtractTextPlugin.extract(options: loader | object) |
86 |
| -``` |
87 |
| - |
88 |
| -Creates an extracting loader from an existing loader. Supports loaders of type `{ loader: [name]-loader -> {String}, options: {} -> {Object} }`. |
89 | 44 |
|
90 |
| -|Name|Type|Description| |
91 |
| -|:--:|:--:|:----------| |
92 |
| -|**`options.use`**|`{String}`/`{Array}`/`{Object}`|Loader(s) that should be used for converting the resource to a CSS exporting module _(required)_| |
93 |
| -|**`options.fallback`**|`{String}`/`{Array}`/`{Object}`|loader(e.g `'style-loader'`) that should be used when the CSS is not extracted (i.e. in an additional chunk when `allChunks: false`)| |
94 |
| -|**`options.publicPath`**|`{String}`|Override the `publicPath` setting for this loader| |
| 45 | +## Info |
95 | 46 |
|
| 47 | +It moves all the `require("style.css")`s in entry chunks ***AND DYNAMIC CODE SPLIT CHUNKS*** into a separate ***multiple*** CSS files. So your styles are no longer inlined into the JS bundle, but separate in CSS bundle files (e.g named entry points: `main.12345.css` and dynamic split chunks: `0.123456.css`, `1.123456.css`, etc). |
96 | 48 |
|
97 |
| -#### Multiple Instances |
| 49 | +If you effectively use code-splitting this can be a far better option than using emerging solutions like *StyleStron*, *StyledComponents*,and slightly older tools like *Aphrodite*, *Glamor*, etc. We don't like either rounds of tools because they all have a runtime overhead. Every time your React component is rendered with those, CSS is generated and updated within the DOM. The reason *Extract CSS Chunk* can be a better option is because *we also generate multiple sets of CSS* based on what is actually "used", but without the runtime overhead. The difference is our definition of "used" is modules determined statically (which may not in fact be rendered) vs. what is actually rendered (as is the case with the other tools). |
98 | 50 |
|
99 |
| -There is also an `extract` function on the instance. You should use this if you have more than one instance of `ExtractTextPlugin`. |
100 |
| - |
101 |
| -```js |
102 |
| -const ExtractTextPlugin = require('extract-text-webpack-plugin'); |
103 |
| - |
104 |
| -// Create multiple instances |
105 |
| -const extractCSS = new ExtractTextPlugin('stylesheets/[name]-one.css'); |
106 |
| -const extractLESS = new ExtractTextPlugin('stylesheets/[name]-two.css'); |
107 |
| - |
108 |
| -module.exports = { |
109 |
| - module: { |
110 |
| - rules: [ |
111 |
| - { |
112 |
| - test: /\.css$/, |
113 |
| - use: extractCSS.extract([ 'css-loader', 'postcss-loader' ]) |
114 |
| - }, |
115 |
| - { |
116 |
| - test: /\.less$/i, |
117 |
| - use: extractLESS.extract([ 'css-loader', 'less-loader' ]) |
118 |
| - }, |
119 |
| - ] |
120 |
| - }, |
121 |
| - plugins: [ |
122 |
| - extractCSS, |
123 |
| - extractLESS |
124 |
| - ] |
125 |
| -}; |
126 |
| -``` |
| 51 | +So yes, our CSS files may be mildly larger and include unnecessary css, but it's CSS that is likely to be used, i.e. if an "if/else" statement reaches another branch, *but not CSS from a different section of your app.* |
127 | 52 |
|
128 |
| -### Extracting Sass or LESS |
| 53 | +In short, by putting code splitting appropriate places you have a lot of control over the css files that are created. **It's our perspective that you have achieved 80-99% of the performance gains (i.e. the creation of small relevant css files) at this static stage. Offloading this work to the runtime stage is ultimately nit-picking and results in diminishing returns.** |
129 | 54 |
|
130 |
| -The configuration is the same, switch out `sass-loader` for `less-loader` when necessary. |
| 55 | +ADDITIONAL BENEFIT: **This also means you DO NOT need to clutter your component code with a specialized way of applying CSS!** A final cherry on top is that the way you import module-based styles is exactly how you would import styles in React Native that exist in a separate file, which allows for extremely interchangeable code between React Native and regular React. Hurray! |
131 | 56 |
|
132 |
| -```js |
133 |
| -const ExtractTextPlugin = require('extract-text-webpack-plugin'); |
| 57 | +**We love CSS modules; no less, no more.** |
134 | 58 |
|
135 |
| -module.exports = { |
136 |
| - module: { |
137 |
| - rules: [ |
138 |
| - { |
139 |
| - test: /\.scss$/, |
140 |
| - use: ExtractTextPlugin.extract({ |
141 |
| - fallback: 'style-loader', |
142 |
| - //resolve-url-loader may be chained before sass-loader if necessary |
143 |
| - use: ['css-loader', 'sass-loader'] |
144 |
| - }) |
145 |
| - } |
146 |
| - ] |
147 |
| - }, |
148 |
| - plugins: [ |
149 |
| - new ExtractTextPlugin('style.css') |
150 |
| - //if you want to pass in options, you can do so: |
151 |
| - //new ExtractTextPlugin({ |
152 |
| - // filename: 'style.css' |
153 |
| - //}) |
154 |
| - ] |
155 |
| -} |
156 |
| -``` |
| 59 | +## NOTE |
157 | 60 |
|
158 |
| -### Modify filename |
| 61 | +The file name structure is currently hard-coded to be `[name].[contenthash].css`. It was first created to be used with *React Loadable* which will discover your CSS files for you (from webpack stats) no matter what you name them--so it's not something you need to worry about. If you want to fix that and therefore allow for a user-specified `filename` like in the original *Extract Text Plugin*, feel free to make a PR. The current filename structure is required for HMR so that new files are created on each change--so that is the problem you're trying to solve. For whatever reason, if the file name is the same (i.e. doesn't contain a hash) the original file is not updated. There are some notes in the code. Check the `hotModuleReplacement.js` file. |
159 | 62 |
|
160 |
| -`filename` parameter could be `Function`. It passes `getPath` to process the format like `css/[name].css` and returns the real file name, `css/js/a.css`. You can replace `css/js` with `css` then you will get the new path `css/a.css`. |
161 | 63 |
|
| 64 | +[npm]: https://img.shields.io/npm/v/extract-css-chunk.svg |
| 65 | +[npm-url]: https://npmjs.com/package/extract-css-chunk |
162 | 66 |
|
163 |
| -```js |
164 |
| -entry: { |
165 |
| - 'js/a': "./a" |
166 |
| -}, |
167 |
| -plugins: [ |
168 |
| - new ExtractTextPlugin({ |
169 |
| - filename: (getPath) => { |
170 |
| - return getPath('css/[name].css').replace('css/js', 'css'); |
171 |
| - }, |
172 |
| - allChunks: true |
173 |
| - }) |
174 |
| -] |
175 |
| -``` |
| 67 | +[tests]: http://img.shields.io/travis/faceyspacey/extract-css-chunk.svg |
| 68 | +[tests-url]: https://travis-ci.org/faceyspacey/extract-css-chunk |
176 | 69 |
|
177 |
| -<h2 align="center">Maintainers</h2> |
178 |
| - |
179 |
| -<table> |
180 |
| - <tbody> |
181 |
| - <tr> |
182 |
| - <td align="center"> |
183 |
| - <img width="150" height="150" |
184 |
| - src="https://avatars3.githubusercontent.com/u/166921?v=3&s=150"> |
185 |
| - </br> |
186 |
| - <a href="https://github.com/bebraw">Juho Vepsäläinen</a> |
187 |
| - </td> |
188 |
| - <td align="center"> |
189 |
| - <img width="150" height="150" |
190 |
| - src="https://avatars2.githubusercontent.com/u/8420490?v=3&s=150"> |
191 |
| - </br> |
192 |
| - <a href="https://github.com/d3viant0ne">Joshua Wiens</a> |
193 |
| - </td> |
194 |
| - <td align="center"> |
195 |
| - <img width="150" height="150" |
196 |
| - src="https://avatars3.githubusercontent.com/u/533616?v=3&s=150"> |
197 |
| - </br> |
198 |
| - <a href="https://github.com/SpaceK33z">Kees Kluskens</a> |
199 |
| - </td> |
200 |
| - <td align="center"> |
201 |
| - <img width="150" height="150" |
202 |
| - src="https://avatars3.githubusercontent.com/u/3408176?v=3&s=150"> |
203 |
| - </br> |
204 |
| - <a href="https://github.com/TheLarkInn">Sean Larkin</a> |
205 |
| - </td> |
206 |
| - </tr> |
207 |
| - <tbody> |
208 |
| -</table> |
209 |
| - |
210 |
| - |
211 |
| -[npm]: https://img.shields.io/npm/v/extract-text-webpack-plugin.svg |
212 |
| -[npm-url]: https://npmjs.com/package/extract-text-webpack-plugin |
213 |
| - |
214 |
| -[node]: https://img.shields.io/node/v/extract-text-webpack-plugin.svg |
215 |
| -[node-url]: https://nodejs.org |
216 |
| - |
217 |
| -[deps]: https://david-dm.org/webpack-contrib/extract-text-webpack-plugin.svg |
218 |
| -[deps-url]: https://david-dm.org/webpack-contrib/extract-text-webpack-plugin |
219 |
| - |
220 |
| -[tests]: http://img.shields.io/travis/webpack-contrib/extract-text-webpack-plugin.svg |
221 |
| -[tests-url]: https://travis-ci.org/webpack-contrib/extract-text-webpack-plugin |
222 |
| - |
223 |
| -[cover]: https://coveralls.io/repos/github/webpack-contrib/extract-text-webpack-plugin/badge.svg |
224 |
| -[cover-url]: https://coveralls.io/github/webpack-contrib/extract-text-webpack-plugin |
225 |
| - |
226 |
| -[chat]: https://badges.gitter.im/webpack/webpack.svg |
227 |
| -[chat-url]: https://gitter.im/webpack/webpack |
| 70 | +[chat]: https://badges.gitter.im/extract-css-chunk.svg |
| 71 | +[chat-url]: https://gitter.im/extract-css-chunk |
0 commit comments