Skip to content

Commit 49f3ff0

Browse files
refactor: loader (webpack-contrib#956)
1 parent 0672e78 commit 49f3ff0

15 files changed

+300
-354
lines changed

src/index.js

+44-36
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ import {
1919
normalizeSourceMap,
2020
getModulesPlugins,
2121
getImportPrefix,
22-
getIcssItemReplacer,
2322
getFilter,
24-
getRuntimeCode,
23+
getApiCode,
2524
getImportCode,
2625
getModuleCode,
2726
getExportCode,
27+
prepareCode,
2828
} from './utils';
2929
import Warning from './Warning';
3030
import CssSyntaxError from './CssSyntaxError';
@@ -37,14 +37,9 @@ export default function loader(content, map, meta) {
3737
const callback = this.async();
3838
const sourceMap = options.sourceMap || false;
3939

40-
if (sourceMap && map) {
41-
// eslint-disable-next-line no-param-reassign
42-
map = normalizeSourceMap(map);
43-
} else {
44-
// Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
45-
// eslint-disable-next-line no-param-reassign
46-
map = null;
47-
}
40+
// Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
41+
// eslint-disable-next-line no-param-reassign
42+
map = sourceMap && map ? normalizeSourceMap(map) : null;
4843

4944
// Reuse CSS AST (PostCSS AST e.g 'postcss-loader') to avoid reparsing
5045
if (meta) {
@@ -62,11 +57,22 @@ export default function loader(content, map, meta) {
6257
plugins.push(...getModulesPlugins(options, this));
6358
}
6459

65-
plugins.push(icssParser());
60+
// Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
61+
const importPrefix = getImportPrefix(this, options.importLoaders);
62+
63+
plugins.push(
64+
icssParser({
65+
loaderContext: this,
66+
importPrefix,
67+
exportLocalsStyle: options.exportLocalsStyle,
68+
})
69+
);
6670

6771
if (options.import !== false) {
6872
plugins.push(
6973
importParser({
74+
loaderContext: this,
75+
importPrefix,
7076
filter: getFilter(options.import, this.resourcePath),
7177
})
7278
);
@@ -75,6 +81,7 @@ export default function loader(content, map, meta) {
7581
if (options.url !== false) {
7682
plugins.push(
7783
urlParser({
84+
loaderContext: this,
7885
filter: getFilter(options.url, this.resourcePath, (value) =>
7986
isUrlRequest(value)
8087
),
@@ -108,36 +115,37 @@ export default function loader(content, map, meta) {
108115
result.messages = [];
109116
}
110117

111-
const {
112-
exportOnlyLocals: onlyLocals,
113-
exportLocalsStyle: localsStyle,
114-
} = options;
115-
// Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
116-
const importPrefix = getImportPrefix(this, options.importLoaders);
117-
// Prepare replacer to change from `___CSS_LOADER_IMPORT___INDEX___` to `require('./file.css').locals`
118-
const replacer = getIcssItemReplacer(
119-
result,
120-
this,
121-
importPrefix,
122-
onlyLocals
123-
);
118+
const { exportOnlyLocals: onlyLocals } = options;
124119

125-
// eslint-disable-next-line no-param-reassign
126-
result.cssLoaderBuildInfo = {
127-
onlyLocals,
128-
localsStyle,
129-
importPrefix,
130-
replacer,
131-
};
120+
const importItems = result.messages
121+
.filter((message) => (message.type === 'import' ? message : false))
122+
.reduce((accumulator, currentValue) => {
123+
accumulator.push(currentValue.import);
124+
125+
return accumulator;
126+
}, []);
127+
const exportItems = result.messages
128+
.filter((message) => (message.type === 'export' ? message : false))
129+
.reduce((accumulator, currentValue) => {
130+
accumulator.push(currentValue.export);
131+
132+
return accumulator;
133+
}, []);
132134

133-
const runtimeCode = getRuntimeCode(result, this, sourceMap);
134-
const importCode = getImportCode(result, this);
135-
const moduleCode = getModuleCode(result);
136-
const exportsCode = getExportCode(result);
135+
const importCode = getImportCode(importItems, onlyLocals);
136+
const moduleCode = getModuleCode(result, sourceMap, onlyLocals);
137+
const exportCode = getExportCode(exportItems, onlyLocals);
138+
const apiCode = getApiCode(this, sourceMap, onlyLocals);
137139

138140
return callback(
139141
null,
140-
runtimeCode + importCode + moduleCode + exportsCode
142+
prepareCode(
143+
{ apiCode, importCode, moduleCode, exportCode },
144+
result.messages,
145+
this,
146+
importPrefix,
147+
onlyLocals
148+
)
141149
);
142150
})
143151
.catch((error) => {

src/plugins/postcss-icss-parser.js

+20-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import postcss from 'postcss';
22
import { extractICSS, replaceValueSymbols, replaceSymbols } from 'icss-utils';
33
import loaderUtils from 'loader-utils';
44

5+
import { getExportItemCode, getImportItemCode } from '../utils';
6+
57
const pluginName = 'postcss-icss-parser';
68

79
function hasImportMessage(messages, url) {
@@ -16,7 +18,7 @@ function hasImportMessage(messages, url) {
1618

1719
export default postcss.plugin(
1820
pluginName,
19-
() =>
21+
(options = {}) =>
2022
function process(css, result) {
2123
const importReplacements = Object.create(null);
2224
const { icssImports, icssExports } = extractICSS(css);
@@ -37,10 +39,18 @@ export default postcss.plugin(
3739
});
3840

3941
if (!hasImportMessage(result.messages, url)) {
42+
const media = '';
43+
const { loaderContext, importPrefix } = options;
44+
4045
result.messages.push({
4146
pluginName,
4247
type: 'import',
43-
item: { url, media: '' },
48+
import: getImportItemCode(
49+
{ url, media },
50+
loaderContext,
51+
importPrefix
52+
),
53+
item: { url, media },
4454
});
4555
}
4656
}
@@ -49,16 +59,17 @@ export default postcss.plugin(
4959
replaceSymbols(css, importReplacements);
5060

5161
for (const exportName of Object.keys(icssExports)) {
62+
const name = exportName;
63+
const value = replaceValueSymbols(
64+
icssExports[name],
65+
importReplacements
66+
);
67+
5268
result.messages.push({
5369
pluginName,
70+
export: getExportItemCode(name, value, options.exportLocalsStyle),
5471
type: 'export',
55-
item: {
56-
key: exportName,
57-
value: replaceValueSymbols(
58-
icssExports[exportName],
59-
importReplacements
60-
),
61-
},
72+
item: { name, value },
6273
});
6374
}
6475
}

src/plugins/postcss-import-parser.js

+15-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import postcss from 'postcss';
22
import valueParser from 'postcss-value-parser';
33

4+
import { uniqWith, getImportItemCode } from '../utils';
5+
46
const pluginName = 'postcss-import-parser';
57

68
function getArg(nodes) {
@@ -84,25 +86,26 @@ function walkAtRules(css, result, filter) {
8486
return items;
8587
}
8688

87-
function uniq(array) {
88-
return array.reduce(
89-
(acc, d) =>
90-
!acc.find((el) => el.url === d.url && el.media === d.media)
91-
? [...acc, d]
92-
: acc,
93-
[]
94-
);
95-
}
96-
9789
export default postcss.plugin(
9890
pluginName,
9991
(options = {}) =>
10092
function process(css, result) {
10193
const traversed = walkAtRules(css, result, options.filter);
102-
const paths = uniq(traversed);
94+
const paths = uniqWith(
95+
traversed,
96+
(value, other) => value.url === other.url && value.media === other.media
97+
);
10398

10499
paths.forEach((item) => {
105-
result.messages.push({ pluginName, type: 'import', item });
100+
result.messages.push({
101+
pluginName,
102+
type: 'import',
103+
import: getImportItemCode(
104+
item,
105+
options.loaderContext,
106+
options.importPrefix
107+
),
108+
});
106109
});
107110
}
108111
);

src/plugins/postcss-url-parser.js

+25-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import postcss from 'postcss';
22
import valueParser from 'postcss-value-parser';
33

4+
import { uniqWith, flatten, getUrlHelperCode, getUrlItemCode } from '../utils';
5+
46
const pluginName = 'postcss-url-parser';
57

68
const isUrlFunc = /url/i;
@@ -102,29 +104,15 @@ function walkDeclsWithUrl(css, result, filter) {
102104
return items;
103105
}
104106

105-
function uniqWith(array, comparator) {
106-
return array.reduce(
107-
(acc, d) => (!acc.some((item) => comparator(d, item)) ? [...acc, d] : acc),
108-
[]
109-
);
110-
}
111-
112-
function flatten(array) {
113-
return array.reduce((a, b) => a.concat(b), []);
114-
}
115-
116-
function isEqual(value, other) {
117-
return value.url === other.url && value.needQuotes === other.needQuotes;
118-
}
119-
120107
export default postcss.plugin(
121108
pluginName,
122109
(options = {}) =>
123110
function process(css, result) {
124111
const traversed = walkDeclsWithUrl(css, result, options.filter);
125112
const paths = uniqWith(
126113
flatten(traversed.map((item) => item.urls)),
127-
isEqual
114+
(value, other) =>
115+
value.url === other.url && value.needQuotes === other.needQuotes
128116
);
129117

130118
if (paths.length === 0) {
@@ -133,16 +121,35 @@ export default postcss.plugin(
133121

134122
const placeholders = [];
135123

124+
let hasUrlHelper = false;
125+
136126
paths.forEach((path, index) => {
127+
const { loaderContext } = options;
137128
const placeholder = `___CSS_LOADER_URL___${index}___`;
138129
const { url, needQuotes } = path;
139130

140131
placeholders.push({ placeholder, path });
141132

133+
if (!hasUrlHelper) {
134+
result.messages.push({
135+
pluginName,
136+
type: 'import',
137+
import: getUrlHelperCode(loaderContext),
138+
});
139+
140+
// eslint-disable-next-line no-param-reassign
141+
hasUrlHelper = true;
142+
}
143+
142144
result.messages.push({
143145
pluginName,
144-
type: 'url',
145-
item: { url, placeholder, needQuotes },
146+
type: 'import',
147+
import: getUrlItemCode(
148+
{ url, placeholder, needQuotes },
149+
loaderContext
150+
),
151+
importType: 'url',
152+
placeholder,
146153
});
147154
});
148155

src/runtime/get-url.js renamed to src/runtime/getUrl.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module.exports = function escape(url, needQuotes) {
1+
module.exports = (url, needQuotes) => {
22
if (typeof url !== 'string') {
33
return url;
44
}

0 commit comments

Comments
 (0)