css-loader 2.0.1 → 3.0.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");
@@ -43,27 +33,10 @@ function loader(content, map, meta) {
43
33
  const options = (0, _loaderUtils.getOptions)(this) || {};
44
34
  (0, _schemaUtils.default)(_options.default, options, 'CSS Loader');
45
35
  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
36
+ const sourceMap = options.sourceMap || false; // Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
37
+ // eslint-disable-next-line no-param-reassign
66
38
 
39
+ map = sourceMap && map ? (0, _utils.normalizeSourceMap)(map) : null; // Reuse CSS AST (PostCSS AST e.g 'postcss-loader') to avoid reparsing
67
40
 
68
41
  if (meta) {
69
42
  const {
@@ -79,186 +52,69 @@ function loader(content, map, meta) {
79
52
  const plugins = [];
80
53
 
81
54
  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
- }
55
+ plugins.push(...(0, _utils.getModulesPlugins)(options, this));
56
+ } // Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
57
+
58
+
59
+ const importPrefix = (0, _utils.getImportPrefix)(this, options.importLoaders);
60
+ plugins.push((0, _plugins.icssParser)({
61
+ loaderContext: this,
62
+ importPrefix,
63
+ localsConvention: options.localsConvention
64
+ }));
98
65
 
99
66
  if (options.import !== false) {
100
67
  plugins.push((0, _plugins.importParser)({
68
+ loaderContext: this,
69
+ importPrefix,
101
70
  filter: (0, _utils.getFilter)(options.import, this.resourcePath)
102
71
  }));
103
72
  }
104
73
 
105
74
  if (options.url !== false) {
106
75
  plugins.push((0, _plugins.urlParser)({
76
+ loaderContext: this,
107
77
  filter: (0, _utils.getFilter)(options.url, this.resourcePath, value => (0, _loaderUtils.isUrlRequest)(value))
108
78
  }));
109
79
  }
110
80
 
111
- plugins.push((0, _plugins.icssParser)());
112
81
  (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()}`,
82
+ from: (0, _loaderUtils.getRemainingRequest)(this).split('!').pop(),
115
83
  to: (0, _loaderUtils.getCurrentRequest)(this).split('!').pop(),
116
84
  map: options.sourceMap ? {
117
85
  prev: map,
118
- sourcesContent: true,
119
86
  inline: false,
120
87
  annotation: false
121
88
  } : null
122
89
  }).then(result => {
123
90
  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
91
 
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
- }
92
+ if (!result.messages) {
93
+ // eslint-disable-next-line no-param-reassign
94
+ result.messages = [];
95
+ }
198
96
 
97
+ const {
98
+ onlyLocals
99
+ } = options;
100
+ const importItems = result.messages.filter(message => message.type === 'import' ? message : false).reduce((accumulator, currentValue) => {
101
+ accumulator.push(currentValue.import);
199
102
  return accumulator;
200
103
  }, []);
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);
104
+ const exportItems = result.messages.filter(message => message.type === 'export' ? message : false).reduce((accumulator, currentValue) => {
105
+ accumulator.push(currentValue.export);
106
+ return accumulator;
107
+ }, []);
108
+ const importCode = (0, _utils.getImportCode)(importItems, onlyLocals);
109
+ const moduleCode = (0, _utils.getModuleCode)(result, sourceMap, onlyLocals);
110
+ const exportCode = (0, _utils.getExportCode)(exportItems, onlyLocals);
111
+ const apiCode = (0, _utils.getApiCode)(this, sourceMap, onlyLocals);
112
+ return callback(null, (0, _utils.prepareCode)({
113
+ apiCode,
114
+ importCode,
115
+ moduleCode,
116
+ exportCode
117
+ }, result.messages, this, importPrefix, onlyLocals));
262
118
  }).catch(error => {
263
119
  callback(error.name === 'CssSyntaxError' ? new _CssSyntaxError.default(error) : error);
264
120
  });
package/dist/options.json CHANGED
@@ -29,63 +29,70 @@
29
29
  {
30
30
  "type": "string",
31
31
  "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
32
  },
59
33
  {
60
- "instanceof": "Function"
34
+ "type": "object",
35
+ "additionalProperties": false,
36
+ "properties": {
37
+ "mode": {
38
+ "type": "string",
39
+ "enum": ["local", "global"]
40
+ },
41
+ "localIdentName": {
42
+ "type": "string"
43
+ },
44
+ "localIdentRegExp": {
45
+ "anyOf": [
46
+ {
47
+ "type": "string"
48
+ },
49
+ {
50
+ "instanceof": "RegExp"
51
+ }
52
+ ]
53
+ },
54
+ "context": {
55
+ "type": "string"
56
+ },
57
+ "hashPrefix": {
58
+ "type": "string"
59
+ },
60
+ "getLocalIdent": {
61
+ "anyOf": [
62
+ {
63
+ "type": "boolean"
64
+ },
65
+ {
66
+ "instanceof": "Function"
67
+ }
68
+ ]
69
+ }
70
+ }
61
71
  }
62
72
  ]
63
73
  },
64
74
  "sourceMap": {
65
75
  "type": "boolean"
66
76
  },
67
- "camelCase": {
77
+ "importLoaders": {
68
78
  "anyOf": [
69
79
  {
70
80
  "type": "boolean"
71
81
  },
72
82
  {
73
- "type": "string",
74
- "enum": ["dashes", "only", "dashesOnly"]
83
+ "type": "number"
75
84
  }
76
85
  ]
77
86
  },
78
- "importLoaders": {
87
+ "localsConvention": {
79
88
  "anyOf": [
80
89
  {
81
- "type": "boolean"
82
- },
83
- {
84
- "type": "number"
90
+ "type": "string",
91
+ "enum": ["asIs", "camelCase", "camelCaseOnly", "dashes", "dashesOnly"]
85
92
  }
86
93
  ]
87
94
  },
88
- "exportOnlyLocals": {
95
+ "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
  });