Skip to content

Commit e20ba8e

Browse files
refactor: use runtime message api for @import
1 parent 2f769b3 commit e20ba8e

File tree

5 files changed

+154
-124
lines changed

5 files changed

+154
-124
lines changed

.eslintrc.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ rules:
99
array-bracket-spacing: 'off'
1010
array-callback-return: error
1111
arrow-body-style: error
12-
arrow-parens: error
12+
arrow-parens: 'off'
1313
arrow-spacing: error
1414
block-scoped-var: 'off'
1515
block-spacing:
@@ -90,7 +90,7 @@ rules:
9090
no-bitwise: error
9191
no-caller: error
9292
no-catch-shadow: error
93-
no-confusing-arrow: error
93+
no-confusing-arrow: 'off'
9494
no-continue: error
9595
no-div-regex: error
9696
no-duplicate-imports: error
@@ -176,7 +176,7 @@ rules:
176176
no-useless-constructor: error
177177
no-useless-escape: error
178178
no-useless-rename: error
179-
no-useless-return: error
179+
no-useless-return: 'off'
180180
no-var: 'off'
181181
no-void: error
182182
no-warning-comments: error

lib/getImportPrefix.js

-20
This file was deleted.

lib/loader.js

+41-59
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
MIT License http://www.opensource.org/licenses/mit-license.php
33
Author Tobias Koppers @sokra
44
*/
5+
56
const loaderUtils = require("loader-utils");
67
const postcss = require("postcss");
78
const plugin = require("./plugin");
8-
const getImportPrefix = require("./getImportPrefix");
99
const SyntaxError = require("./SyntaxError");
1010

1111
module.exports = function(content, map, meta) {
@@ -42,7 +42,9 @@ module.exports = function(content, map, meta) {
4242
const plugins = [
4343
plugin({
4444
url: options.url !== false,
45-
import: options.import !== false
45+
import: options.import !== false,
46+
loaderContext: this,
47+
importLoaders: options.importLoaders
4648
})
4749
];
4850

@@ -71,52 +73,13 @@ module.exports = function(content, map, meta) {
7173
postcss(plugins)
7274
.process(content, postcssOptions)
7375
.then(result => {
76+
if (meta && meta.messages) {
77+
result.messages = result.messages.concat(meta.messages);
78+
}
79+
7480
let cssAsString = JSON.stringify(result.css);
75-
let imports = "";
76-
let exports = "";
7781
let urlEscapeHelperCode = "";
7882

79-
if (options.import !== false) {
80-
const alreadyImported = {};
81-
imports = result.messages
82-
.filter(message => message.type === "at-rule-import")
83-
.filter(message => {
84-
if (!message.mediaQuery) {
85-
if (alreadyImported[message.url]) {
86-
return false;
87-
}
88-
89-
alreadyImported[message.url] = true;
90-
}
91-
92-
return true;
93-
})
94-
.map(message => {
95-
if (!loaderUtils.isUrlRequest(message.url)) {
96-
return (
97-
"exports.push([module.id, " +
98-
JSON.stringify("@import url(" + message.url + ");") +
99-
", " +
100-
JSON.stringify(message.mediaQuery) +
101-
"]);"
102-
);
103-
}
104-
105-
// for importing CSS
106-
var importUrlPrefix = getImportPrefix(this, options);
107-
var importUrl = importUrlPrefix + message.url;
108-
109-
return (
110-
"exports.i(require(" +
111-
loaderUtils.stringifyRequest(this, importUrl) +
112-
"), " +
113-
JSON.stringify(message.mediaQuery) +
114-
");"
115-
);
116-
})
117-
.join("\n");
118-
}
119-
12083
if (options.url !== false) {
12184
urlEscapeHelperCode =
12285
"var runtimeEscape = require(" +
@@ -142,6 +105,27 @@ module.exports = function(content, map, meta) {
142105
});
143106
}
144107

108+
let runtime = "";
109+
110+
if (result.messages && result.messages.length > 0) {
111+
runtime = result.messages
112+
.filter(message => (message.type === "runtime" ? message : false))
113+
.reduce((initialValue, message) => {
114+
try {
115+
message =
116+
typeof message.runtimeCode === "function"
117+
? message.runtimeCode(this)
118+
: message.runtimeCode;
119+
120+
initialValue += message;
121+
} catch (err) {
122+
this.emitError(err);
123+
}
124+
125+
return initialValue;
126+
}, "");
127+
}
128+
145129
if (sourceMap && result.map) {
146130
map = result.map.toJSON();
147131

@@ -162,33 +146,31 @@ module.exports = function(content, map, meta) {
162146
map = JSON.stringify(map);
163147
}
164148

165-
const runtimeCode = `module.exports = exports = require(${loaderUtils.stringifyRequest(
166-
this,
167-
require.resolve("./runtime.js")
168-
)})(${!!sourceMap});\n`;
169-
const moduleCode = `// CSS Module\nexports.push([module.id, ${cssAsString}, ""${
170-
map ? `,${map}` : ""
171-
}]);\n`;
172-
const importsCode = imports ? `// CSS Imports\n${imports}\n` : "";
173149
// Todo need save backward compatibility with old `style-loader` and exports.locals
174-
const exportsCode = exports ? `// CSS Exports\n${exports}\n` : false;
175-
176150
cb(
177151
null,
178152
[
179153
urlEscapeHelperCode,
180-
runtimeCode,
181-
importsCode,
182-
moduleCode,
183-
exportsCode
154+
`module.exports = exports = require(${loaderUtils.stringifyRequest(
155+
this,
156+
require.resolve("./runtime.js")
157+
)})(${!!sourceMap});\n`,
158+
runtime ? `// CSS Exports\n${runtime}\n` : "",
159+
`// CSS Module\nexports.push([module.id, ${cssAsString}, ""${
160+
map ? `,${map}` : ""
161+
}]);\n`
184162
].join("\n")
185163
);
164+
165+
return;
186166
})
187167
.catch(err => {
188168
if (err.file) {
189169
this.addDependency(err.file);
190170
}
191171

192172
cb(err.name === "CssSyntaxError" ? new SyntaxError(err) : err);
173+
174+
return;
193175
});
194176
};

lib/plugin.js

+50-11
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,28 @@ const loaderUtils = require("loader-utils");
44

55
const pluginName = "postcss-css-loader";
66

7+
function getImportPrefix(loaderContext, importLoaders) {
8+
if (importLoaders === false) {
9+
return "";
10+
}
11+
12+
const importLoadersValue = parseInt(importLoaders, 10) || 0;
13+
const loadersRequest = loaderContext.loaders
14+
.slice(
15+
loaderContext.loaderIndex,
16+
loaderContext.loaderIndex + 1 + importLoadersValue
17+
)
18+
.map(x => x.request)
19+
.join("!");
20+
21+
return "-!" + loadersRequest + "!";
22+
}
23+
724
module.exports = postcss.plugin(pluginName, function(options) {
825
return function(css, result) {
926
if (options.import) {
27+
const alreadyImported = {};
28+
1029
css.walkAtRules(/^import$/i, function(rule) {
1130
const parsedValue = valueParser(rule.params);
1231

@@ -35,20 +54,39 @@ module.exports = postcss.plugin(pluginName, function(options) {
3554
return;
3655
}
3756

57+
const mediaQuery = valueParser
58+
.stringify(parsedValue.nodes.slice(1))
59+
.trim();
60+
61+
let runtimeCode = "";
62+
3863
if (loaderUtils.isUrlRequest(url)) {
3964
url = loaderUtils.urlToRequest(url);
65+
66+
const importUrlPrefix = getImportPrefix(
67+
options.loaderContext,
68+
options.importLoaders
69+
);
70+
71+
runtimeCode = `exports.i(require(${loaderUtils.stringifyRequest(
72+
options.loaderContext,
73+
importUrlPrefix + url
74+
)}), ${JSON.stringify(mediaQuery)});\n`;
75+
} else {
76+
runtimeCode = `exports.push([module.id, ${JSON.stringify(
77+
"@import url(" + url + ");"
78+
)}, ${JSON.stringify(mediaQuery)}]);`;
4079
}
4180

42-
const mediaQuery = valueParser
43-
.stringify(parsedValue.nodes.slice(1))
44-
.trim();
81+
if (!alreadyImported[url]) {
82+
result.messages.push({
83+
pluginName,
84+
type: "runtime",
85+
runtimeCode
86+
});
4587

46-
result.messages.push({
47-
pluginName,
48-
type: "at-rule-import",
49-
url: url,
50-
mediaQuery: mediaQuery
51-
});
88+
alreadyImported[url] = true;
89+
}
5290

5391
rule.remove();
5492
});
@@ -92,7 +130,8 @@ module.exports = postcss.plugin(pluginName, function(options) {
92130
node.after = "";
93131

94132
const requestedURL = loaderUtils.urlToRequest(URLValue);
95-
const placeholder = "___CSS_LOADER_IMPORT_URL_PLACEHOLDER___" + index + "___";
133+
const placeholder =
134+
"___CSS_LOADER_IMPORT_URL_PLACEHOLDER___" + index + "___";
96135

97136
URLNode.value = placeholder;
98137
// Strip quotes, they will be re-added if the module needs them
@@ -105,7 +144,7 @@ module.exports = postcss.plugin(pluginName, function(options) {
105144
url: requestedURL
106145
});
107146

108-
index++;
147+
index += 1;
109148

110149
return false;
111150
})

0 commit comments

Comments
 (0)