css-loader 2.0.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11,18 +11,8 @@ var _postcss = _interopRequireDefault(require("postcss"));
11
11
 
12
12
  var _package = _interopRequireDefault(require("postcss/package.json"));
13
13
 
14
- var _postcssModulesLocalByDefault = _interopRequireDefault(require("postcss-modules-local-by-default"));
15
-
16
- var _postcssModulesExtractImports = _interopRequireDefault(require("postcss-modules-extract-imports"));
17
-
18
- var _postcssModulesScope = _interopRequireDefault(require("postcss-modules-scope"));
19
-
20
- var _postcssModulesValues = _interopRequireDefault(require("postcss-modules-values"));
21
-
22
14
  var _loaderUtils = require("loader-utils");
23
15
 
24
- var _camelCase = _interopRequireDefault(require("lodash/camelCase"));
25
-
26
16
  var _options = _interopRequireDefault(require("./options.json"));
27
17
 
28
18
  var _plugins = require("./plugins");
@@ -41,29 +31,15 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
41
31
  */
42
32
  function loader(content, map, meta) {
43
33
  const options = (0, _loaderUtils.getOptions)(this) || {};
44
- (0, _schemaUtils.default)(_options.default, options, 'CSS Loader');
34
+ (0, _schemaUtils.default)(_options.default, options, {
35
+ name: 'CSS Loader',
36
+ baseDataPath: 'options'
37
+ });
45
38
  const callback = this.async();
46
- const sourceMap = options.sourceMap || false;
47
- /* eslint-disable no-param-reassign */
48
-
49
- if (sourceMap) {
50
- if (map) {
51
- if (typeof map === 'string') {
52
- map = JSON.stringify(map);
53
- }
54
-
55
- if (map.sources) {
56
- map.sources = map.sources.map(source => source.replace(/\\/g, '/'));
57
- map.sourceRoot = '';
58
- }
59
- }
60
- } else {
61
- // Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
62
- map = null;
63
- }
64
- /* eslint-enable no-param-reassign */
65
- // Reuse CSS AST (PostCSS AST e.g 'postcss-loader') to avoid reparsing
39
+ const sourceMap = options.sourceMap || false; // Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
40
+ // eslint-disable-next-line no-param-reassign
66
41
 
42
+ map = sourceMap && map ? (0, _utils.normalizeSourceMap)(map) : null; // Reuse CSS AST (PostCSS AST e.g 'postcss-loader') to avoid reparsing
67
43
 
68
44
  if (meta) {
69
45
  const {
@@ -79,186 +55,69 @@ function loader(content, map, meta) {
79
55
  const plugins = [];
80
56
 
81
57
  if (options.modules) {
82
- const loaderContext = this;
83
- const mode = typeof options.modules === 'boolean' ? 'local' : options.modules;
84
- plugins.push(_postcssModulesValues.default, (0, _postcssModulesLocalByDefault.default)({
85
- mode
86
- }), (0, _postcssModulesExtractImports.default)(), (0, _postcssModulesScope.default)({
87
- generateScopedName: function generateScopedName(exportName) {
88
- const localIdentName = options.localIdentName || '[hash:base64]';
89
- const customGetLocalIdent = options.getLocalIdent || _utils.getLocalIdent;
90
- return customGetLocalIdent(loaderContext, localIdentName, exportName, {
91
- regExp: options.localIdentRegExp,
92
- hashPrefix: options.hashPrefix || '',
93
- context: options.context
94
- });
95
- }
96
- }));
97
- }
58
+ plugins.push(...(0, _utils.getModulesPlugins)(options, this));
59
+ } // Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
60
+
61
+
62
+ const importPrefix = (0, _utils.getImportPrefix)(this, options.importLoaders);
63
+ plugins.push((0, _plugins.icssParser)({
64
+ loaderContext: this,
65
+ importPrefix,
66
+ localsConvention: options.localsConvention
67
+ }));
98
68
 
99
69
  if (options.import !== false) {
100
70
  plugins.push((0, _plugins.importParser)({
71
+ loaderContext: this,
72
+ importPrefix,
101
73
  filter: (0, _utils.getFilter)(options.import, this.resourcePath)
102
74
  }));
103
75
  }
104
76
 
105
77
  if (options.url !== false) {
106
78
  plugins.push((0, _plugins.urlParser)({
79
+ loaderContext: this,
107
80
  filter: (0, _utils.getFilter)(options.url, this.resourcePath, value => (0, _loaderUtils.isUrlRequest)(value))
108
81
  }));
109
82
  }
110
83
 
111
- plugins.push((0, _plugins.icssParser)());
112
84
  (0, _postcss.default)(plugins).process(content, {
113
- // we need a prefix to avoid path rewriting of PostCSS
114
- from: `/css-loader!${(0, _loaderUtils.getRemainingRequest)(this).split('!').pop()}`,
85
+ from: (0, _loaderUtils.getRemainingRequest)(this).split('!').pop(),
115
86
  to: (0, _loaderUtils.getCurrentRequest)(this).split('!').pop(),
116
87
  map: options.sourceMap ? {
117
88
  prev: map,
118
- sourcesContent: true,
119
89
  inline: false,
120
90
  annotation: false
121
91
  } : null
122
92
  }).then(result => {
123
93
  result.warnings().forEach(warning => this.emitWarning(new _Warning.default(warning)));
124
- const messages = result.messages || []; // Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
125
-
126
- const importUrlPrefix = (0, _utils.getImportPrefix)(this, options.importLoaders); // Prepare replacer to change from `___CSS_LOADER_IMPORT___INDEX___` to `require('./file.css').locals`
127
-
128
- const importItemReplacer = placeholder => {
129
- const match = _utils.placholderRegExps.importItem.exec(placeholder);
130
-
131
- const idx = Number(match[1]);
132
- const message = messages.find( // eslint-disable-next-line no-shadow
133
- message => message.type === 'icss-import' && message.item && message.item.index === idx);
134
-
135
- if (!message) {
136
- return placeholder;
137
- }
138
-
139
- const {
140
- item
141
- } = message;
142
- const importUrl = importUrlPrefix + (0, _loaderUtils.urlToRequest)(item.url);
143
-
144
- if (options.exportOnlyLocals) {
145
- return `" + require(${(0, _loaderUtils.stringifyRequest)(this, importUrl)})[${JSON.stringify(item.export)}] + "`;
146
- }
147
-
148
- return `" + require(${(0, _loaderUtils.stringifyRequest)(this, importUrl)}).locals[${JSON.stringify(item.export)}] + "`;
149
- };
150
-
151
- const exports = messages.filter(message => message.type === 'export').reduce((accumulator, message) => {
152
- const {
153
- key,
154
- value
155
- } = message.item;
156
- let valueAsString = JSON.stringify(value);
157
- valueAsString = valueAsString.replace(_utils.placholderRegExps.importItemG, importItemReplacer);
158
-
159
- function addEntry(k) {
160
- accumulator.push(`\t${JSON.stringify(k)}: ${valueAsString}`);
161
- }
162
-
163
- let targetKey;
164
-
165
- switch (options.camelCase) {
166
- case true:
167
- addEntry(key);
168
- targetKey = (0, _camelCase.default)(key);
169
-
170
- if (targetKey !== key) {
171
- addEntry(targetKey);
172
- }
173
94
 
174
- break;
175
-
176
- case 'dashes':
177
- addEntry(key);
178
- targetKey = (0, _utils.dashesCamelCase)(key);
179
-
180
- if (targetKey !== key) {
181
- addEntry(targetKey);
182
- }
183
-
184
- break;
185
-
186
- case 'only':
187
- addEntry((0, _camelCase.default)(key));
188
- break;
189
-
190
- case 'dashesOnly':
191
- addEntry((0, _utils.dashesCamelCase)(key));
192
- break;
193
-
194
- default:
195
- addEntry(key);
196
- break;
197
- }
95
+ if (!result.messages) {
96
+ // eslint-disable-next-line no-param-reassign
97
+ result.messages = [];
98
+ }
198
99
 
100
+ const {
101
+ onlyLocals
102
+ } = options;
103
+ const importItems = result.messages.filter(message => message.type === 'import' ? message : false).reduce((accumulator, currentValue) => {
104
+ accumulator.push(currentValue.import);
199
105
  return accumulator;
200
106
  }, []);
201
-
202
- if (options.exportOnlyLocals) {
203
- return callback(null, exports.length > 0 ? `module.exports = {\n${exports.join(',\n')}\n};` : '');
204
- }
205
-
206
- const imports = messages.filter(message => message.type === 'import').map(message => {
207
- const {
208
- url
209
- } = message.item;
210
- const media = message.item.media || '';
211
-
212
- if (!(0, _loaderUtils.isUrlRequest)(url)) {
213
- return `exports.push([module.id, ${JSON.stringify(`@import url(${url});`)}, ${JSON.stringify(media)}]);`;
214
- }
215
-
216
- const importUrl = importUrlPrefix + (0, _loaderUtils.urlToRequest)(url);
217
- return `exports.i(require(${(0, _loaderUtils.stringifyRequest)(this, importUrl)}), ${JSON.stringify(media)});`;
218
- }, this);
219
- let cssAsString = JSON.stringify(result.css).replace(_utils.placholderRegExps.importItemG, importItemReplacer); // Helper for ensuring valid CSS strings from requires
220
-
221
- let hasUrlEscapeHelper = false;
222
- messages.filter(message => message.type === 'url').forEach(message => {
223
- if (!hasUrlEscapeHelper) {
224
- imports.push(`var urlEscape = require(${(0, _loaderUtils.stringifyRequest)(this, require.resolve('./runtime/url-escape.js'))});`);
225
- hasUrlEscapeHelper = true;
226
- }
227
-
228
- const {
229
- item
230
- } = message;
231
- const {
232
- url,
233
- placeholder
234
- } = item; // Remove `#hash` and `?#hash` from `require`
235
-
236
- const [normalizedUrl, singleQuery, hashValue] = url.split(/(\?)?#/);
237
- const hash = singleQuery || hashValue ? `"${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}"` : '';
238
- imports.push(`var ${placeholder} = urlEscape(require(${(0, _loaderUtils.stringifyRequest)(this, (0, _loaderUtils.urlToRequest)(normalizedUrl))})${hash ? ` + ${hash}` : ''});`);
239
- cssAsString = cssAsString.replace(new RegExp(placeholder, 'g'), () => `" + ${placeholder} + "`);
240
- });
241
- let newMap = result.map;
242
-
243
- if (sourceMap && newMap) {
244
- // Add a SourceMap
245
- newMap = newMap.toJSON();
246
-
247
- if (newMap.sources) {
248
- newMap.sources = newMap.sources.map(source => source.split('!').pop().replace(/\\/g, '/'), this);
249
- newMap.sourceRoot = '';
250
- }
251
-
252
- newMap.file = newMap.file.split('!').pop().replace(/\\/g, '/');
253
- newMap = JSON.stringify(newMap);
254
- }
255
-
256
- const runtimeCode = `exports = module.exports = require(${(0, _loaderUtils.stringifyRequest)(this, require.resolve('./runtime/api'))})(${!!sourceMap});\n`;
257
- const importCode = imports.length > 0 ? `// Imports\n${imports.join('\n')}\n\n` : '';
258
- const moduleCode = `// Module\nexports.push([module.id, ${cssAsString}, ""${newMap ? `,${newMap}` : ''}]);\n\n`;
259
- const exportsCode = exports.length > 0 ? `// Exports\nexports.locals = {\n${exports.join(',\n')}\n};` : ''; // Embed runtime
260
-
261
- return callback(null, runtimeCode + importCode + moduleCode + exportsCode);
107
+ const exportItems = result.messages.filter(message => message.type === 'export' ? message : false).reduce((accumulator, currentValue) => {
108
+ accumulator.push(currentValue.export);
109
+ return accumulator;
110
+ }, []);
111
+ const importCode = (0, _utils.getImportCode)(importItems, onlyLocals);
112
+ const moduleCode = (0, _utils.getModuleCode)(result, sourceMap, onlyLocals);
113
+ const exportCode = (0, _utils.getExportCode)(exportItems, onlyLocals);
114
+ const apiCode = (0, _utils.getApiCode)(this, sourceMap, onlyLocals);
115
+ return callback(null, (0, _utils.prepareCode)({
116
+ apiCode,
117
+ importCode,
118
+ moduleCode,
119
+ exportCode
120
+ }, result.messages, this, importPrefix, onlyLocals));
262
121
  }).catch(error => {
263
122
  callback(error.name === 'CssSyntaxError' ? new _CssSyntaxError.default(error) : error);
264
123
  });
package/dist/options.json CHANGED
@@ -2,6 +2,7 @@
2
2
  "additionalProperties": false,
3
3
  "properties": {
4
4
  "url": {
5
+ "description": "Enables/Disables 'url'/'image-set' functions handling (https://github.com/webpack-contrib/css-loader#url).",
5
6
  "anyOf": [
6
7
  {
7
8
  "type": "boolean"
@@ -12,6 +13,7 @@
12
13
  ]
13
14
  },
14
15
  "import": {
16
+ "description": "Enables/Disables '@import' at-rules handling (https://github.com/webpack-contrib/css-loader#import).",
15
17
  "anyOf": [
16
18
  {
17
19
  "type": "boolean"
@@ -22,60 +24,60 @@
22
24
  ]
23
25
  },
24
26
  "modules": {
27
+ "description": "Enables/Disables CSS Modules and their configuration (https://github.com/webpack-contrib/css-loader#modules).",
25
28
  "anyOf": [
26
29
  {
27
30
  "type": "boolean"
28
31
  },
29
32
  {
30
- "type": "string",
31
33
  "enum": ["local", "global"]
32
- }
33
- ]
34
- },
35
- "localIdentName": {
36
- "type": "string"
37
- },
38
- "localIdentRegExp": {
39
- "anyOf": [
40
- {
41
- "type": "string"
42
- },
43
- {
44
- "instanceof": "RegExp"
45
- }
46
- ]
47
- },
48
- "context": {
49
- "type": "string"
50
- },
51
- "hashPrefix": {
52
- "type": "string"
53
- },
54
- "getLocalIdent": {
55
- "anyOf": [
56
- {
57
- "type": "boolean"
58
34
  },
59
35
  {
60
- "instanceof": "Function"
36
+ "type": "object",
37
+ "additionalProperties": false,
38
+ "properties": {
39
+ "mode": {
40
+ "enum": ["local", "global"]
41
+ },
42
+ "localIdentName": {
43
+ "type": "string"
44
+ },
45
+ "localIdentRegExp": {
46
+ "anyOf": [
47
+ {
48
+ "type": "string"
49
+ },
50
+ {
51
+ "instanceof": "RegExp"
52
+ }
53
+ ]
54
+ },
55
+ "context": {
56
+ "type": "string"
57
+ },
58
+ "hashPrefix": {
59
+ "type": "string"
60
+ },
61
+ "getLocalIdent": {
62
+ "anyOf": [
63
+ {
64
+ "type": "boolean"
65
+ },
66
+ {
67
+ "instanceof": "Function"
68
+ }
69
+ ]
70
+ }
71
+ }
61
72
  }
62
73
  ]
63
74
  },
64
75
  "sourceMap": {
76
+ "description": "Enables/Disables generation of source maps (https://github.com/webpack-contrib/css-loader#sourcemap).",
65
77
  "type": "boolean"
66
78
  },
67
- "camelCase": {
68
- "anyOf": [
69
- {
70
- "type": "boolean"
71
- },
72
- {
73
- "type": "string",
74
- "enum": ["dashes", "only", "dashesOnly"]
75
- }
76
- ]
77
- },
78
79
  "importLoaders": {
80
+ "description": "Enables/Disables or setups number of loaders applied before CSS loader (https://github.com/webpack-contrib/css-loader#importloaders).",
79
81
  "anyOf": [
80
82
  {
81
83
  "type": "boolean"
@@ -85,7 +87,12 @@
85
87
  }
86
88
  ]
87
89
  },
88
- "exportOnlyLocals": {
90
+ "localsConvention": {
91
+ "description": "Style of exported classnames (https://github.com/webpack-contrib/css-loader#localsconvention).",
92
+ "enum": ["asIs", "camelCase", "camelCaseOnly", "dashes", "dashesOnly"]
93
+ },
94
+ "onlyLocals": {
95
+ "description": "Export only locals (https://github.com/webpack-contrib/css-loader#onlylocals).",
89
96
  "type": "boolean"
90
97
  }
91
98
  },
@@ -7,95 +7,81 @@ exports.default = void 0;
7
7
 
8
8
  var _postcss = _interopRequireDefault(require("postcss"));
9
9
 
10
- var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
11
-
12
10
  var _icssUtils = require("icss-utils");
13
11
 
14
12
  var _loaderUtils = _interopRequireDefault(require("loader-utils"));
15
13
 
14
+ var _utils = require("../utils");
15
+
16
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
17
 
18
18
  const pluginName = 'postcss-icss-parser';
19
19
 
20
- var _default = _postcss.default.plugin(pluginName, () => function process(css, result) {
21
- const imports = {};
22
- const icss = (0, _icssUtils.extractICSS)(css);
23
- const exports = icss.icssExports;
24
- Object.keys(icss.icssImports).forEach(key => {
25
- const url = _loaderUtils.default.parseString(key);
20
+ function hasImportMessage(messages, url) {
21
+ return messages.find(message => message.pluginName === pluginName && message.type === 'import' && message.item.url === url && message.item.media === '');
22
+ }
26
23
 
27
- Object.keys(icss.icssImports[key]).forEach(prop => {
28
- const index = Object.keys(imports).length;
29
- imports[`$${prop}`] = index;
30
- result.messages.push({
31
- pluginName,
32
- type: 'icss-import',
33
- item: {
34
- url,
35
- export: icss.icssImports[key][prop],
36
- index
37
- }
38
- });
39
- const alreadyIncluded = result.messages.find(message => message.pluginName === pluginName && message.type === 'import' && message.item.url === url && message.item.media === '');
24
+ var _default = _postcss.default.plugin(pluginName, (options = {}) => function process(css, result) {
25
+ const importReplacements = Object.create(null);
26
+ const {
27
+ icssImports,
28
+ icssExports
29
+ } = (0, _icssUtils.extractICSS)(css);
30
+ let index = 0;
40
31
 
41
- if (alreadyIncluded) {
42
- return;
43
- }
32
+ for (const importUrl of Object.keys(icssImports)) {
33
+ const url = _loaderUtils.default.parseString(importUrl);
44
34
 
35
+ for (const token of Object.keys(icssImports[importUrl])) {
36
+ index += 1;
37
+ importReplacements[token] = `___CSS_LOADER_IMPORT___${index}___`;
45
38
  result.messages.push({
46
39
  pluginName,
47
- type: 'import',
40
+ type: 'icss-import',
48
41
  item: {
49
42
  url,
50
- media: ''
43
+ export: icssImports[importUrl][token],
44
+ index
51
45
  }
52
46
  });
53
- });
54
- });
55
-
56
- function replaceImportsInString(str) {
57
- const tokens = (0, _postcssValueParser.default)(str);
58
- tokens.walk(node => {
59
- if (node.type !== 'word') {
60
- return;
61
- }
62
-
63
- const token = node.value;
64
- const importIndex = imports[`$${token}`];
65
47
 
66
- if (typeof importIndex === 'number') {
67
- // eslint-disable-next-line no-param-reassign
68
- node.value = `___CSS_LOADER_IMPORT___${importIndex}___`;
48
+ if (!hasImportMessage(result.messages, url)) {
49
+ const media = '';
50
+ const {
51
+ loaderContext,
52
+ importPrefix
53
+ } = options;
54
+ result.messages.push({
55
+ pluginName,
56
+ type: 'import',
57
+ import: (0, _utils.getImportItemCode)({
58
+ url,
59
+ media
60
+ }, loaderContext, importPrefix),
61
+ item: {
62
+ url,
63
+ media
64
+ }
65
+ });
69
66
  }
70
- });
71
- return tokens.toString();
72
- } // Replace tokens in declarations
73
-
74
-
75
- css.walkDecls(decl => {
76
- // eslint-disable-next-line no-param-reassign
77
- decl.value = replaceImportsInString(decl.value.toString());
78
- }); // Replace tokens in at-rules
79
-
80
- css.walkAtRules(atrule => {
81
- // Due reusing `ast` from `postcss-loader` some plugins may lack
82
- // `params` property, we need to account for this possibility
83
- if (atrule.params) {
84
- // eslint-disable-next-line no-param-reassign
85
- atrule.params = replaceImportsInString(atrule.params.toString());
86
67
  }
87
- }); // Replace tokens in export
68
+ }
69
+
70
+ (0, _icssUtils.replaceSymbols)(css, importReplacements);
88
71
 
89
- Object.keys(exports).forEach(exportName => {
72
+ for (const exportName of Object.keys(icssExports)) {
73
+ const name = exportName;
74
+ const value = (0, _icssUtils.replaceValueSymbols)(icssExports[name], importReplacements);
90
75
  result.messages.push({
91
76
  pluginName,
77
+ export: (0, _utils.getExportItemCode)(name, value, options.localsConvention),
92
78
  type: 'export',
93
79
  item: {
94
- key: exportName,
95
- value: replaceImportsInString(exports[exportName])
80
+ name,
81
+ value
96
82
  }
97
83
  });
98
- });
84
+ }
99
85
  });
100
86
 
101
87
  exports.default = _default;
@@ -9,6 +9,8 @@ var _postcss = _interopRequireDefault(require("postcss"));
9
9
 
10
10
  var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
11
11
 
12
+ var _utils = require("../utils");
13
+
12
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
15
 
14
16
  const pluginName = 'postcss-import-parser';
@@ -91,18 +93,14 @@ function walkAtRules(css, result, filter) {
91
93
  return items;
92
94
  }
93
95
 
94
- function uniq(array) {
95
- return array.reduce((acc, d) => !acc.find(el => el.url === d.url && el.media === d.media) ? [...acc, d] : acc, []);
96
- }
97
-
98
96
  var _default = _postcss.default.plugin(pluginName, (options = {}) => function process(css, result) {
99
97
  const traversed = walkAtRules(css, result, options.filter);
100
- const paths = uniq(traversed);
98
+ const paths = (0, _utils.uniqWith)(traversed, (value, other) => value.url === other.url && value.media === other.media);
101
99
  paths.forEach(item => {
102
100
  result.messages.push({
103
101
  pluginName,
104
102
  type: 'import',
105
- item
103
+ import: (0, _utils.getImportItemCode)(item, options.loaderContext, options.importPrefix)
106
104
  });
107
105
  });
108
106
  });