Skip to content

Commit c7233be

Browse files
committed
add loader processing
1 parent 41a547c commit c7233be

File tree

9 files changed

+206
-17
lines changed

9 files changed

+206
-17
lines changed

runtime/index.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export function a(array) {
2+
array.toString = function() {
3+
// T O D O
4+
return this;
5+
}
6+
}
7+
8+
export function b(id, source, sourceMap) {
9+
return [id, source, "", sourceMap];
10+
}
11+
12+
export function c(id, source) {
13+
return b(id, source, null);
14+
}
15+
16+
export function d(data, mediaQuery) {
17+
return data.map(function(item) {
18+
return [item[0], item[1], joinMediaQuery(item[2], mediaQuery), item[3]];
19+
})
20+
}
21+
22+
function joinMediaQuery(itemA, itemB) {
23+
if(itemA && itemB) return "(" + itemA + ") and (" + itemB + ")";
24+
return itemA || itemB || "";
25+
}

src/index.js

+90-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import loaderUtils from 'loader-utils';
66
import parse from './parse';
77

88
export default function loader(source, map) {
9-
const options = loaderUtils.getOptions(this);
9+
const options = loaderUtils.getOptions(this) || {};
1010
const remainingRequest = loaderUtils.getRemainingRequest(this);
1111
const parseResult = parse(source);
1212

@@ -19,7 +19,96 @@ export default function loader(source, map) {
1919
replacer = new ReplaceSource(new RawSource(source), remainingRequest);
2020
}
2121

22+
const includedStylesheets = new Set();
23+
const includedStylesheetsMediaQuery = new Map();
24+
25+
parseResult.atImports.forEach((imp) => {
26+
if(loaderUtils.isUrlRequest(imp.url, options.root)) {
27+
const request = loaderUtils.urlToRequest(imp.url, options.root);
28+
replacer.replace(imp.start, imp.end, '');
29+
includedStylesheets.add(request);
30+
includedStylesheetsMediaQuery.set(request, imp.mediaQuery.join(' '));
31+
}
32+
});
33+
34+
let columns = true;
35+
const importedNames = new Map();
36+
37+
parseResult.imports.forEach((imp) => {
38+
importedNames.set(imp.alias, imp);
39+
});
40+
41+
const declarations = [];
42+
const importReplacements = new Map();
43+
44+
let id = 0;
45+
for(const pair of importedNames) {
46+
const internalName = `cssLoaderImport${id}_${pair[1].importName}`;
47+
id += 1;
48+
importReplacements.set(pair[0], internalName);
49+
declarations.push(`import { ${pair[1].importName} as ${internalName} } from ${JSON.stringify(pair[1].from)};`);
50+
includedStylesheets.add(pair[1].from);
51+
}
52+
53+
for(const pair of importReplacements) {
54+
const identifier = parseResult.identifiers.get(pair[0]);
55+
if(identifier) {
56+
columns = false;
57+
const length = identifier.name.length;
58+
identifier.locations.forEach((loc) => {
59+
replacer.replace(loc, loc + length - 1, `$CSS$LOADER$\{${pair[1]}}`);
60+
});
61+
}
62+
}
63+
2264
parseResult.metablocks.forEach((block) => {
2365
replacer.replace(block.start, block.end, '');
2466
});
67+
68+
const includedStylesheetsArray = [];
69+
for(const include of includedStylesheets) {
70+
const internalName = `cssLoaderImport${id}`;
71+
id += 1;
72+
declarations.push(`import ${internalName} from ${loaderUtils.stringifyRequest(this, include)};`);
73+
includedStylesheetsArray.push({
74+
name: internalName,
75+
mediaQuery: includedStylesheetsMediaQuery.get(include) || ''
76+
});
77+
}
78+
79+
let css;
80+
let sourceMap;
81+
if(options.sourceMap) {
82+
const sourceAndMap = replacer.sourceAndMap(typeof options.sourceMap === 'object' ? options.sourceMap : {
83+
columns: columns
84+
});
85+
css = sourceAndMap.code;
86+
sourceMap = sourceAndMap.map;
87+
} else {
88+
css = replacer.source();
89+
sourceMap = null;
90+
}
91+
92+
const cssJs = JSON.stringify(css).replace(/\$CSS\$LOADER\$\{([^}]+)\}/g, (match, identifer) => `" + ${identifer} + "`);
93+
94+
return [
95+
'// css runtime',
96+
`import * as runtime from ${loaderUtils.stringifyRequest(this, require.resolve("../runtime"))};`,
97+
'',
98+
'// declarations',
99+
declarations.join('\n'),
100+
'',
101+
'// CSS',
102+
'export default runtime.a([',
103+
].concat(
104+
includedStylesheetsArray.map((include) => {
105+
if(!include.mediaQuery) return ` ${include.name},`;
106+
return ` runtime.d(${include.name}, ${JSON.stringify(include.mediaQuery)},`;
107+
})
108+
).concat([
109+
sourceMap ?
110+
` runtime.b(module.id, ${cssJs}, ${sourceMap})` :
111+
` runtime.c(module.id, ${cssJs})`,
112+
']);'
113+
]).join('\n');
25114
}

src/parse-at-import.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function atImportMediaMatch(match) {
2727
}
2828

2929
function atImportEndMatch(match, index, length) {
30-
this.currentItem.end = index + length;
30+
this.currentItem.end = index + length - 1;
3131
return 'topLevel';
3232
}
3333

src/parse-common.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export function throwUnexpectedToken(match, index, length, state) {
33
}
44

55
export function metablockEndMatch(match, index, length) {
6-
this.currentBlock.end = index + length;
6+
this.currentBlock.end = index + length - 1;
77
this.currentImport = undefined;
88
return 'topLevel';
99
}

src/parse-import.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ function importFromRawMatch(match, index) {
2525
function importAliasMatch(match) {
2626
const importItem = {
2727
alias: match,
28-
importName: null
28+
importName: null,
29+
from: this.currentImport,
2930
};
3031
this.imports.push(importItem);
3132
this.currentItem = importItem;
+35-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,37 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`loader should process simple.css 1`] = `undefined`;
3+
exports[`loader should process import.css 1`] = `
4+
Array [
5+
"// css runtime
6+
import * as runtime from \\"../runtime/index.js\\";
7+
8+
// declarations
9+
import { ABC as cssLoaderImport0_ABC } from \\"some-file\\";
10+
import { DEF as cssLoaderImport1_DEF } from \\"some-file\\";
11+
import { HIJ as cssLoaderImport2_HIJ } from \\"other-file\\";
12+
import cssLoaderImport3 from \\"some-file\\";
13+
import cssLoaderImport4 from \\"other-file\\";
14+
15+
// CSS
16+
export default runtime.a([
17+
cssLoaderImport3,
18+
cssLoaderImport4,
19+
runtime.c(module.id, \\"body {\\\\n background: \\" + cssLoaderImport0_ABC + \\" \\" + cssLoaderImport1_DEF + \\" \\" + cssLoaderImport2_HIJ + \\" klm\\\\n}\\\\n\\\\n.\\" + cssLoaderImport0_ABC + \\" { \\" + cssLoaderImport1_DEF + \\": \\" + cssLoaderImport2_HIJ + \\"; }\\\\n\\")
20+
]);",
21+
]
22+
`;
23+
24+
exports[`loader should process simple.css 1`] = `
25+
Array [
26+
"// css runtime
27+
import * as runtime from \\"../runtime/index.js\\";
28+
29+
// declarations
30+
31+
32+
// CSS
33+
export default runtime.a([
34+
runtime.c(module.id, \\"body {\\\\n background: red;\\\\n}\\\\n\\\\n.class {\\\\n color: rgb(1, 2, 3);\\\\n}\\\\n\\")
35+
]);",
36+
]
37+
`;

test/__snapshots__/parse.test.js.snap

+15-11
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ exports[`parse should parse at-import.css 1`] = `
44
Object {
55
"atImports": Array [
66
Object {
7-
"end": 15,
7+
"end": 14,
88
"mediaQuery": Array [],
99
"start": 0,
1010
"url": "abc",
1111
},
1212
Object {
13-
"end": 35,
13+
"end": 34,
1414
"mediaQuery": Array [],
1515
"start": 15,
1616
"url": "abc",
1717
},
1818
Object {
19-
"end": 64,
19+
"end": 63,
2020
"mediaQuery": Array [
2121
"print,",
2222
"screen",
@@ -25,7 +25,7 @@ Object {
2525
"url": "abc",
2626
},
2727
Object {
28-
"end": 173,
28+
"end": 172,
2929
"mediaQuery": Array [
3030
"screen",
3131
"print",
@@ -48677,19 +48677,19 @@ Object {
4867748677
"imports": Array [],
4867848678
"metablocks": Array [
4867948679
Object {
48680-
"end": 37,
48680+
"end": 36,
4868148681
"start": 0,
4868248682
},
4868348683
Object {
48684-
"end": 51,
48684+
"end": 50,
4868548685
"start": 37,
4868648686
},
4868748687
Object {
48688-
"end": 112,
48688+
"end": 111,
4868948689
"start": 51,
4869048690
},
4869148691
Object {
48692-
"end": 233,
48692+
"end": 232,
4869348693
"start": 112,
4869448694
},
4869548695
],
@@ -48786,32 +48786,36 @@ Object {
4878648786
"imports": Array [
4878748787
Object {
4878848788
"alias": "_imp_abc",
48789+
"from": "some-file.css",
4878948790
"importName": "abc",
4879048791
},
4879148792
Object {
4879248793
"alias": "_imp_def",
48794+
"from": "some-file.css",
4879348795
"importName": "def",
4879448796
},
4879548797
Object {
4879648798
"alias": "--hoho",
48799+
"from": "abc",
4879748800
"importName": "abc",
4879848801
},
4879948802
Object {
4880048803
"alias": "__123hihi",
48804+
"from": "sum(\\"zzz\\")",
4880148805
"importName": "__123hihi",
4880248806
},
4880348807
],
4880448808
"metablocks": Array [
4880548809
Object {
48806-
"end": 64,
48810+
"end": 63,
4880748811
"start": 0,
4880848812
},
4880948813
Object {
48810-
"end": 96,
48814+
"end": 95,
4881148815
"start": 64,
4881248816
},
4881348817
Object {
48814-
"end": 249,
48818+
"end": 248,
4881548819
"start": 96,
4881648820
},
4881748821
],

test/loader-fixtures/import.css

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
:import(some-file) {
2+
abc: ABC;
3+
def: DEF;
4+
}
5+
6+
:import(other-file) {
7+
hij: HIJ;
8+
}
9+
10+
:export {
11+
xyz: abc def hij klm;
12+
}
13+
14+
body {
15+
background: abc def hij klm
16+
}
17+
18+
.abc { def: hij; }

test/loader.test.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,25 @@ describe('loader', () => {
1111
it(`should process ${filename}`, () => {
1212
const filepath = path.resolve(fixtures, filename);
1313
const content = fs.readFileSync(filepath, 'utf-8').replace(/\r\n?/g, '\n');
14-
const result = loader.call({}, content);
14+
let result;
15+
const directResult = loader.call({
16+
request: "css-loader!file.css",
17+
loaders: [
18+
{
19+
path: "css-loader",
20+
},
21+
],
22+
context: __dirname,
23+
currentLoaderIndex: 0,
24+
sourceMap: false,
25+
callback(err, ...args) {
26+
if(err) {
27+
throw err;
28+
}
29+
result = args;
30+
}
31+
}, content);
32+
result = result || [directResult];
1533
expect(result).toMatchSnapshot();
1634
});
1735
});

0 commit comments

Comments
 (0)