Skip to content

Commit 2f769b3

Browse files
refactor: loader
1 parent ff7a4c8 commit 2f769b3

File tree

3 files changed

+80
-76
lines changed

3 files changed

+80
-76
lines changed

lib/loader.js

Lines changed: 76 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ const plugin = require("./plugin");
88
const getImportPrefix = require("./getImportPrefix");
99
const SyntaxError = require("./SyntaxError");
1010

11-
module.exports = function(content, map) {
11+
module.exports = function(content, map, meta) {
1212
const options = loaderUtils.getOptions(this) || {};
1313

1414
// Todo validate options
1515

1616
const cb = this.async();
17-
const sourceMap = options.sourceMap;
17+
const sourceMap = options.sourceMap || false;
1818

1919
if (sourceMap && map) {
2020
if (typeof map === "string") {
@@ -30,85 +30,95 @@ module.exports = function(content, map) {
3030
map = null;
3131
}
3232

33-
// We need a prefix to avoid path rewriting of PostCSS
34-
const from =
35-
"/css-loader!" +
36-
loaderUtils
37-
.getRemainingRequest(this)
38-
.split("!")
39-
.pop();
40-
const to = loaderUtils
41-
.getCurrentRequest(this)
42-
.split("!")
43-
.pop();
33+
// Reuse CSS AST (PostCSS AST e.g 'postcss-loader') to avoid reparsing
34+
if (meta) {
35+
const { ast } = meta;
36+
37+
if (ast && ast.type === "postcss") {
38+
content = ast.root;
39+
}
40+
}
4441

45-
postcss([
42+
const plugins = [
4643
plugin({
4744
url: options.url !== false,
4845
import: options.import !== false
4946
})
50-
])
51-
.process(content, {
52-
from,
53-
to,
54-
map: sourceMap
55-
? {
56-
prev: map,
57-
sourcesContent: true,
58-
inline: false,
59-
annotation: false
60-
}
61-
: null
62-
})
47+
];
48+
49+
const postcssOptions = {
50+
// We need a prefix to avoid path rewriting of PostCSS
51+
from:
52+
"/css-loader!" +
53+
loaderUtils
54+
.getRemainingRequest(this)
55+
.split("!")
56+
.pop(),
57+
to: loaderUtils
58+
.getCurrentRequest(this)
59+
.split("!")
60+
.pop(),
61+
map: sourceMap
62+
? {
63+
prev: map,
64+
sourcesContent: true,
65+
inline: false,
66+
annotation: false
67+
}
68+
: null
69+
};
70+
71+
postcss(plugins)
72+
.process(content, postcssOptions)
6373
.then(result => {
64-
var cssAsString = JSON.stringify(result.css);
74+
let cssAsString = JSON.stringify(result.css);
75+
let imports = "";
76+
let exports = "";
77+
let urlEscapeHelperCode = "";
6578

6679
if (options.import !== false) {
67-
var alreadyImported = {};
68-
var importJs = result.messages
80+
const alreadyImported = {};
81+
imports = result.messages
6982
.filter(message => message.type === "at-rule-import")
70-
.filter(imp => {
71-
if (!imp.mediaQuery) {
72-
if (alreadyImported[imp.url]) {
83+
.filter(message => {
84+
if (!message.mediaQuery) {
85+
if (alreadyImported[message.url]) {
7386
return false;
7487
}
7588

76-
alreadyImported[imp.url] = true;
89+
alreadyImported[message.url] = true;
7790
}
7891

7992
return true;
8093
})
81-
.map(imp => {
82-
if (!loaderUtils.isUrlRequest(imp.url)) {
94+
.map(message => {
95+
if (!loaderUtils.isUrlRequest(message.url)) {
8396
return (
8497
"exports.push([module.id, " +
85-
JSON.stringify("@import url(" + imp.url + ");") +
98+
JSON.stringify("@import url(" + message.url + ");") +
8699
", " +
87-
JSON.stringify(imp.mediaQuery) +
100+
JSON.stringify(message.mediaQuery) +
88101
"]);"
89102
);
90103
}
91104

92105
// for importing CSS
93106
var importUrlPrefix = getImportPrefix(this, options);
94-
var importUrl = importUrlPrefix + imp.url;
107+
var importUrl = importUrlPrefix + message.url;
95108

96109
return (
97110
"exports.i(require(" +
98111
loaderUtils.stringifyRequest(this, importUrl) +
99112
"), " +
100-
JSON.stringify(imp.mediaQuery) +
113+
JSON.stringify(message.mediaQuery) +
101114
");"
102115
);
103116
})
104117
.join("\n");
105118
}
106119

107-
// Helper for ensuring valid CSS strings from requires
108-
let urlEscapeHelper = "";
109-
110120
if (options.url !== false) {
111-
urlEscapeHelper =
121+
urlEscapeHelperCode =
112122
"var runtimeEscape = require(" +
113123
loaderUtils.stringifyRequest(
114124
this,
@@ -117,7 +127,7 @@ module.exports = function(content, map) {
117127
");\n";
118128

119129
result.messages
120-
.filter(message => message.type === "css-loader-import-url")
130+
.filter(message => message.type === "function-url")
121131
.forEach(message => {
122132
const { placeholder, url } = message;
123133
const splittedURL = url.split(/(\?)?#/);
@@ -132,15 +142,6 @@ module.exports = function(content, map) {
132142
});
133143
}
134144

135-
// Todo need save backward compatibility with old `style-loader`
136-
var exportJs = "";
137-
138-
if (exportJs) {
139-
exportJs = "exports.locals = " + exportJs + ";";
140-
}
141-
142-
var moduleJs;
143-
144145
if (sourceMap && result.map) {
145146
map = result.map.toJSON();
146147

@@ -159,34 +160,34 @@ module.exports = function(content, map) {
159160
.pop()
160161
.replace(/\\/g, "/");
161162
map = JSON.stringify(map);
162-
163-
moduleJs =
164-
"exports.push([module.id, " + cssAsString + ', "", ' + map + "]);";
165-
} else {
166-
moduleJs = "exports.push([module.id, " + cssAsString + ', ""]);';
167163
}
168164

169-
// embed runtime
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` : "";
173+
// Todo need save backward compatibility with old `style-loader` and exports.locals
174+
const exportsCode = exports ? `// CSS Exports\n${exports}\n` : false;
175+
170176
cb(
171177
null,
172-
urlEscapeHelper +
173-
"exports = module.exports = require(" +
174-
loaderUtils.stringifyRequest(this, require.resolve("./runtime.js")) +
175-
")(" +
176-
sourceMap +
177-
");\n" +
178-
"// imports\n" +
179-
importJs +
180-
"\n\n" +
181-
"// module\n" +
182-
moduleJs +
183-
"\n\n" +
184-
"// exports\n" +
185-
exportJs
178+
[
179+
urlEscapeHelperCode,
180+
runtimeCode,
181+
importsCode,
182+
moduleCode,
183+
exportsCode
184+
].join("\n")
186185
);
187186
})
188187
.catch(err => {
189-
// Todo if (err.file) this.addDependency(err.file)
188+
if (err.file) {
189+
this.addDependency(err.file);
190+
}
190191

191192
cb(err.name === "CssSyntaxError" ? new SyntaxError(err) : err);
192193
});

lib/plugin.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ module.exports = postcss.plugin(pluginName, function(options) {
100100

101101
result.messages.push({
102102
pluginName,
103-
type: "css-loader-import-url",
103+
type: "function-url",
104104
placeholder: placeholder,
105105
url: requestedURL
106106
});

test/helpers.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ function runLoader(loader, input, map, addOptions, callback) {
5656
request: "css-loader!test.css",
5757
emitError: function(message) {
5858
throw new Error(message);
59+
},
60+
addDependency: function (dep) {
61+
// Nothing
5962
}
6063
};
6164
Object.keys(addOptions).forEach(function(key) {

0 commit comments

Comments
 (0)