UNPKG

9.29 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8
9var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
10
11var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
12
13var _postcss = require('postcss');
14
15var _postcss2 = _interopRequireDefault(_postcss);
16
17var _chunk = require('./chunk');
18
19var _chunk2 = _interopRequireDefault(_chunk);
20
21var _SourceMapSource = require('webpack/lib/SourceMapSource');
22
23var _SourceMapSource2 = _interopRequireDefault(_SourceMapSource);
24
25var _RawSource = require('webpack/lib/RawSource');
26
27var _RawSource2 = _interopRequireDefault(_RawSource);
28
29var _loaderUtils = require('loader-utils');
30
31function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
32
33function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
34
35/**
36 * Detect if a file should be considered for CSS splitting.
37 * @param {String} name Name of the file.
38 * @returns {Boolean} True if to consider the file, false otherwise.
39 */
40var isCSS = function isCSS(name) {
41 return (/\.css$/.test(name)
42 );
43};
44
45/**
46 * Remove the trailing `/` from URLs.
47 * @param {String} str The url to strip the trailing slash from.
48 * @returns {String} The stripped url.
49 */
50var strip = function strip(str) {
51 return str.replace(/\/$/, '');
52};
53
54/**
55 * Create a function that generates names based on some input. This uses
56 * webpack's name interpolator under the hood, but since webpack's argument
57 * list is all funny this exists just to simplify things.
58 * @param {String} input Name to be interpolated.
59 * @returns {Function} Function to do the interpolating.
60 */
61var nameInterpolator = function nameInterpolator(input) {
62 return function (_ref) {
63 var file = _ref.file;
64 var content = _ref.content;
65 var index = _ref.index;
66
67 var res = (0, _loaderUtils.interpolateName)({
68 context: '/',
69 resourcePath: '/' + file
70 }, input, {
71 content: content
72 }).replace(/\[part\]/g, index + 1);
73 return res;
74 };
75};
76
77/**
78 * Normalize the `imports` argument to a function.
79 * @param {Boolean|String} input The name of the imports file, or a boolean
80 * to use the default name.
81 * @param {Boolean} preserve True if the default name should not clash.
82 * @returns {Function} Name interpolator.
83 */
84var normalizeImports = function normalizeImports(input, preserve) {
85 switch (typeof input === 'undefined' ? 'undefined' : _typeof(input)) {
86 case 'string':
87 return nameInterpolator(input);
88 case 'boolean':
89 if (input) {
90 if (preserve) {
91 return nameInterpolator('[name]-split.[ext]');
92 }
93 return function (_ref2) {
94 var file = _ref2.file;
95 return file;
96 };
97 }
98 return function () {
99 return false;
100 };
101 default:
102 throw new TypeError();
103 }
104};
105
106/**
107 * Webpack plugin to split CSS assets into multiple files. This is primarily
108 * used for dealing with IE <= 9 which cannot handle more than ~4000 rules
109 * in a single stylesheet.
110 */
111
112var CSSSplitWebpackPlugin = function () {
113 /**
114 * Create new instance of CSSSplitWebpackPlugin.
115 * @param {Number} size Maximum number of rules for a single file.
116 * @param {Boolean|String} imports Truish to generate an additional import
117 * asset. When a boolean use the default name for the asset.
118 * @param {String} filename Control the generated split file name.
119 * @param {Boolean} preserve True to keep the original unsplit file.
120 */
121
122 function CSSSplitWebpackPlugin(_ref3) {
123 var _ref3$size = _ref3.size;
124 var size = _ref3$size === undefined ? 4000 : _ref3$size;
125 var _ref3$imports = _ref3.imports;
126 var imports = _ref3$imports === undefined ? false : _ref3$imports;
127 var _ref3$filename = _ref3.filename;
128 var filename = _ref3$filename === undefined ? '[name]-[part].[ext]' : _ref3$filename;
129 var preserve = _ref3.preserve;
130
131 _classCallCheck(this, CSSSplitWebpackPlugin);
132
133 this.options = {
134 size: size,
135 imports: normalizeImports(imports, preserve),
136 filename: nameInterpolator(filename),
137 preserve: preserve
138 };
139 }
140
141 /**
142 * Generate the split chunks for a given CSS file.
143 * @param {String} key Name of the file.
144 * @param {Object} asset Valid webpack Source object.
145 * @returns {Promise} Promise generating array of new files.
146 */
147
148
149 _createClass(CSSSplitWebpackPlugin, [{
150 key: 'file',
151 value: function file(key, asset) {
152 var _this = this;
153
154 // Use source-maps when possible.
155 var input = asset.sourceAndMap ? asset.sourceAndMap() : {
156 source: asset.source()
157 };
158 var name = function name(i) {
159 return _this.options.filename(_extends({}, asset, {
160 content: input.source,
161 file: key,
162 index: i
163 }));
164 };
165 return (0, _postcss2.default)([(0, _chunk2.default)(_extends({}, this.options, {
166 result: function result(i) {
167 return {
168 to: name(i),
169 from: key,
170 map: {
171 inline: false,
172 prev: input.map
173 }
174 };
175 }
176 }))]).process(input.source, {
177 from: key
178 }).then(function (result) {
179 return Promise.resolve({
180 file: key,
181 chunks: result.chunks.map(function (_ref4, i) {
182 var css = _ref4.css;
183 var map = _ref4.map;
184
185 return new _SourceMapSource2.default(css, name(i), map.toString());
186 })
187 });
188 });
189 }
190
191 /**
192 * Run the plugin against a webpack compiler instance. Roughly it walks all
193 * the chunks searching for CSS files and when it finds one that needs to be
194 * split it does so and replaces the original file in the chunk with the split
195 * ones. If the `imports` option is specified the original file is replaced
196 * with an empty CSS file importing the split files, otherwise the original
197 * file is removed entirely.
198 * @param {Object} compiler Compiler instance
199 * @returns {void}
200 */
201
202 }, {
203 key: 'apply',
204 value: function apply(compiler) {
205 var _this2 = this;
206
207 // Only run on `this-compilation` to avoid injecting the plugin into
208 // sub-compilers as happens when using the `extract-text-webpack-plugin`.
209 compiler.plugin('this-compilation', function (compilation) {
210 var assets = compilation.assets;
211 var publicPath = strip(compilation.options.output.publicPath || './');
212 compilation.plugin('optimize-chunk-assets', function (chunks, done) {
213 var promises = chunks.map(function (chunk) {
214 var input = chunk.files.filter(isCSS);
215 var items = input.map(function (name) {
216 return _this2.file(name, assets[name]);
217 });
218 return Promise.all(items).then(function (entries) {
219 entries.forEach(function (entry) {
220 // Skip the splitting operation for files that result in no
221 // split occuring.
222 if (entry.chunks.length === 1) {
223 return;
224 }
225 // Inject the new files into the chunk.
226 entry.chunks.forEach(function (file) {
227 assets[file._name] = file;
228 chunk.files.push(file._name);
229 });
230 var content = entry.chunks.map(function (file) {
231 return '@import "' + publicPath + '/' + file._name + '";';
232 }).join('\n');
233 var imports = _this2.options.imports(_extends({}, entry, {
234 content: content
235 }));
236 if (!_this2.options.preserve) {
237 chunk.files.splice(chunk.files.indexOf(entry.file), 1);
238 delete assets[entry.file];
239 }
240 if (imports) {
241 assets[imports] = new _RawSource2.default(content);
242 chunk.files.push(imports);
243 }
244 });
245 return Promise.resolve();
246 });
247 });
248 Promise.all(promises).then(function () {
249 done();
250 }, done);
251 });
252 });
253 }
254 }]);
255
256 return CSSSplitWebpackPlugin;
257}();
258
259exports.default = CSSSplitWebpackPlugin;
260//# sourceMappingURL=index.js.map
\No newline at end of file