css-loader 2.1.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 _normalizePath = _interopRequireDefault(require("normalize-path"));
25
-
26
16
  var _options = _interopRequireDefault(require("./options.json"));
27
17
 
28
18
  var _plugins = require("./plugins");
@@ -43,38 +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
- // Some loader emit source map as string
52
- // Strip any JSON XSSI avoidance prefix from the string (as documented in the source maps specification), and then parse the string as JSON.
53
- if (typeof map === 'string') {
54
- map = JSON.parse(map.replace(/^\)]}'[^\n]*\n/, ''));
55
- } // Source maps should use forward slash because it is URLs (https://github.com/mozilla/source-map/issues/91)
56
- // We should normalize path because previous loaders like `sass-loader` using backslash when generate source map
57
-
58
-
59
- if (map.file) {
60
- map.file = (0, _normalizePath.default)(map.file);
61
- }
62
-
63
- if (map.sourceRoot) {
64
- map.sourceRoot = (0, _normalizePath.default)(map.sourceRoot);
65
- }
66
-
67
- if (map.sources) {
68
- map.sources = map.sources.map(source => (0, _normalizePath.default)(source));
69
- }
70
- }
71
- } else {
72
- // Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
73
- map = null;
74
- }
75
- /* eslint-enable no-param-reassign */
76
- // 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
77
38
 
39
+ map = sourceMap && map ? (0, _utils.normalizeSourceMap)(map) : null; // Reuse CSS AST (PostCSS AST e.g 'postcss-loader') to avoid reparsing
78
40
 
79
41
  if (meta) {
80
42
  const {
@@ -90,36 +52,32 @@ function loader(content, map, meta) {
90
52
  const plugins = [];
91
53
 
92
54
  if (options.modules) {
93
- const loaderContext = this;
94
- const mode = typeof options.modules === 'boolean' ? 'local' : options.modules;
95
- plugins.push(_postcssModulesValues.default, (0, _postcssModulesLocalByDefault.default)({
96
- mode
97
- }), (0, _postcssModulesExtractImports.default)(), (0, _postcssModulesScope.default)({
98
- generateScopedName: function generateScopedName(exportName) {
99
- const localIdentName = options.localIdentName || '[hash:base64]';
100
- const customGetLocalIdent = options.getLocalIdent || _utils.getLocalIdent;
101
- return customGetLocalIdent(loaderContext, localIdentName, exportName, {
102
- regExp: options.localIdentRegExp,
103
- hashPrefix: options.hashPrefix || '',
104
- context: options.context
105
- });
106
- }
107
- }));
108
- }
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
+ }));
109
65
 
110
66
  if (options.import !== false) {
111
67
  plugins.push((0, _plugins.importParser)({
68
+ loaderContext: this,
69
+ importPrefix,
112
70
  filter: (0, _utils.getFilter)(options.import, this.resourcePath)
113
71
  }));
114
72
  }
115
73
 
116
74
  if (options.url !== false) {
117
75
  plugins.push((0, _plugins.urlParser)({
76
+ loaderContext: this,
118
77
  filter: (0, _utils.getFilter)(options.url, this.resourcePath, value => (0, _loaderUtils.isUrlRequest)(value))
119
78
  }));
120
79
  }
121
80
 
122
- plugins.push((0, _plugins.icssParser)());
123
81
  (0, _postcss.default)(plugins).process(content, {
124
82
  from: (0, _loaderUtils.getRemainingRequest)(this).split('!').pop(),
125
83
  to: (0, _loaderUtils.getCurrentRequest)(this).split('!').pop(),
@@ -130,130 +88,33 @@ function loader(content, map, meta) {
130
88
  } : null
131
89
  }).then(result => {
132
90
  result.warnings().forEach(warning => this.emitWarning(new _Warning.default(warning)));
133
- const messages = result.messages || []; // Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
134
-
135
- const importUrlPrefix = (0, _utils.getImportPrefix)(this, options.importLoaders); // Prepare replacer to change from `___CSS_LOADER_IMPORT___INDEX___` to `require('./file.css').locals`
136
-
137
- const importItemReplacer = placeholder => {
138
- const match = _utils.placholderRegExps.importItem.exec(placeholder);
139
-
140
- const idx = Number(match[1]);
141
- const message = messages.find( // eslint-disable-next-line no-shadow
142
- message => message.type === 'icss-import' && message.item && message.item.index === idx);
143
-
144
- if (!message) {
145
- return placeholder;
146
- }
147
-
148
- const {
149
- item
150
- } = message;
151
- const importUrl = importUrlPrefix + (0, _loaderUtils.urlToRequest)(item.url);
152
-
153
- if (options.exportOnlyLocals) {
154
- return `" + require(${(0, _loaderUtils.stringifyRequest)(this, importUrl)})[${JSON.stringify(item.export)}] + "`;
155
- }
156
-
157
- return `" + require(${(0, _loaderUtils.stringifyRequest)(this, importUrl)}).locals[${JSON.stringify(item.export)}] + "`;
158
- };
159
-
160
- const exports = messages.filter(message => message.type === 'export').reduce((accumulator, message) => {
161
- const {
162
- key,
163
- value
164
- } = message.item;
165
- let valueAsString = JSON.stringify(value);
166
- valueAsString = valueAsString.replace(_utils.placholderRegExps.importItemG, importItemReplacer);
167
91
 
168
- function addEntry(k) {
169
- accumulator.push(`\t${JSON.stringify(k)}: ${valueAsString}`);
170
- }
171
-
172
- let targetKey;
173
-
174
- switch (options.camelCase) {
175
- case true:
176
- addEntry(key);
177
- targetKey = (0, _utils.camelCase)(key);
178
-
179
- if (targetKey !== key) {
180
- addEntry(targetKey);
181
- }
182
-
183
- break;
184
-
185
- case 'dashes':
186
- addEntry(key);
187
- targetKey = (0, _utils.dashesCamelCase)(key);
188
-
189
- if (targetKey !== key) {
190
- addEntry(targetKey);
191
- }
192
-
193
- break;
194
-
195
- case 'only':
196
- addEntry((0, _utils.camelCase)(key));
197
- break;
198
-
199
- case 'dashesOnly':
200
- addEntry((0, _utils.dashesCamelCase)(key));
201
- break;
202
-
203
- default:
204
- addEntry(key);
205
- break;
206
- }
92
+ if (!result.messages) {
93
+ // eslint-disable-next-line no-param-reassign
94
+ result.messages = [];
95
+ }
207
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);
208
102
  return accumulator;
209
103
  }, []);
210
-
211
- if (options.exportOnlyLocals) {
212
- return callback(null, exports.length > 0 ? `module.exports = {\n${exports.join(',\n')}\n};` : '');
213
- }
214
-
215
- const imports = messages.filter(message => message.type === 'import').map(message => {
216
- const {
217
- url
218
- } = message.item;
219
- const media = message.item.media || '';
220
-
221
- if (!(0, _loaderUtils.isUrlRequest)(url)) {
222
- return `exports.push([module.id, ${JSON.stringify(`@import url(${url});`)}, ${JSON.stringify(media)}]);`;
223
- }
224
-
225
- const importUrl = importUrlPrefix + (0, _loaderUtils.urlToRequest)(url);
226
- return `exports.i(require(${(0, _loaderUtils.stringifyRequest)(this, importUrl)}), ${JSON.stringify(media)});`;
227
- }, this);
228
- let cssAsString = JSON.stringify(result.css).replace(_utils.placholderRegExps.importItemG, importItemReplacer); // Helper for ensuring valid CSS strings from requires
229
-
230
- let hasUrlEscapeHelper = false;
231
- messages.filter(message => message.type === 'url').forEach(message => {
232
- if (!hasUrlEscapeHelper) {
233
- imports.push(`var urlEscape = require(${(0, _loaderUtils.stringifyRequest)(this, require.resolve('./runtime/url-escape.js'))});`);
234
- hasUrlEscapeHelper = true;
235
- }
236
-
237
- const {
238
- item
239
- } = message;
240
- const {
241
- url,
242
- placeholder,
243
- needQuotes
244
- } = item; // Remove `#hash` and `?#hash` from `require`
245
-
246
- const [normalizedUrl, singleQuery, hashValue] = url.split(/(\?)?#/);
247
- const hash = singleQuery || hashValue ? `"${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}"` : '';
248
- imports.push(`var ${placeholder} = urlEscape(require(${(0, _loaderUtils.stringifyRequest)(this, (0, _loaderUtils.urlToRequest)(normalizedUrl))})${hash ? ` + ${hash}` : ''}${needQuotes ? ', true' : ''});`);
249
- cssAsString = cssAsString.replace(new RegExp(placeholder, 'g'), () => `" + ${placeholder} + "`);
250
- });
251
- const runtimeCode = `exports = module.exports = require(${(0, _loaderUtils.stringifyRequest)(this, require.resolve('./runtime/api'))})(${!!sourceMap});\n`;
252
- const importCode = imports.length > 0 ? `// Imports\n${imports.join('\n')}\n\n` : '';
253
- const moduleCode = `// Module\nexports.push([module.id, ${cssAsString}, ""${result.map ? `,${result.map}` : ''}]);\n\n`;
254
- const exportsCode = exports.length > 0 ? `// Exports\nexports.locals = {\n${exports.join(',\n')}\n};` : ''; // Embed runtime
255
-
256
- 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));
257
118
  }).catch(error => {
258
119
  callback(error.name === 'CssSyntaxError' ? new _CssSyntaxError.default(error) : error);
259
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
  });