-
Notifications
You must be signed in to change notification settings - Fork 152
/
Copy pathloader.ts
100 lines (82 loc) · 3.36 KB
/
loader.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import {
Block,
ResolvedConfiguration,
StyleMapping,
resolveConfiguration,
} from "@css-blocks/core";
import * as debugGenerator from "debug";
import * as loaderUtils from "loader-utils";
const debug = debugGenerator("css-blocks:webpack:loader");
import { LoaderContext } from "./context";
import { PendingResult, TmpType } from "./Plugin";
/**
* The css-blocks loader makes css-blocks available to webpack modules.
*/
function trackBlockDependencies(loaderContext: LoaderContext, block: Block, options: ResolvedConfiguration): void {
let sourceFile = options.importer.filesystemPath(block.identifier, options);
if (sourceFile !== null) {
loaderContext.dependency(sourceFile);
}
block.dependencies.forEach(dep => {
loaderContext.dependency(dep);
});
block.transitiveBlockDependencies().forEach(blockDep => {
trackBlockDependencies(loaderContext, blockDep, options);
});
}
// tslint:disable-next-line:prefer-unknown-to-any
export function CSSBlocksWebpackAdapter(this: LoaderContext, source: any, map: any): void {
// Make ourselves async. We'll be waiting for Blocks to finish compiling.
let callback = this.async()!;
if (!callback) { throw new Error("Cannot initialize CSS Blocks async Webpack loader."); }
let thisLoader = this.loaders[this.loaderIndex];
let path = this.resourcePath;
// tslint:disable-next-line:prefer-unknown-to-any
let options: any;
if (thisLoader.options) {
options = thisLoader.options;
} else {
options = loaderUtils.getOptions(this) || {};
}
if (!options.rewriter) {
callback(new Error("No rewriter"));
return;
}
let rewriter = options.rewriter || {};
rewriter.blocks = rewriter.blocks || {};
this.dependency(path);
let cssFileNames = Object.keys(this.cssBlocks.mappings);
let cssBlockOpts: ResolvedConfiguration = resolveConfiguration(this.cssBlocks.compilationOptions);
let metaMappingPromises: PendingResult[] = [];
cssFileNames.forEach(filename => {
metaMappingPromises.push(this.cssBlocks.mappings[filename]);
});
debug(`Waiting for ${metaMappingPromises.length} block compilations to complete...`);
Promise.all(metaMappingPromises)
.then((mappings: (StyleMapping<TmpType> | void)[]) => {
debug(`Completed ${metaMappingPromises.length} block compilations!`);
mappings.forEach((mapping: StyleMapping<TmpType> | void) => {
debug(`StyleMapping has ${ mapping && mapping.blocks.size || 0} blocks`);
if (!mapping) { return; }
// When an css or analysis error happens the mapping seems to be undefined and generates a confusing error.
let styleMapping: StyleMapping<TmpType> | undefined = mapping && mapping.analyses && mapping.analyses.find(a => a.template.identifier === path) && mapping;
if (!styleMapping) {
return;
}
for (let key in styleMapping.blocks) {
let block = styleMapping.blocks[key];
trackBlockDependencies(this, block, cssBlockOpts);
}
rewriter.blocks[path] = styleMapping;
});
callback(null, source, map);
})
.catch((err) => {
debug(`${metaMappingPromises.length} block compilations failed with:\n\n ${err}`);
callback(err);
});
}
export const LOADER = __filename;
// Webpack expects the default export of loaders to be the loader itself.
// tslint:disable-next-line:no-default-export
export default CSSBlocksWebpackAdapter;