-
Notifications
You must be signed in to change notification settings - Fork 282
/
loader.ts
144 lines (122 loc) · 4.44 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import path from 'path';
// @ts-expect-error
import loaderUtils from 'loader-utils';
import {
getPackageInfo,
IdentifierOption,
processVanillaFile,
serializeCss,
transform,
} from '@vanilla-extract/integration';
import type { LoaderContext } from './types';
import { debug, formatResourcePath } from './logger';
import { ChildCompiler } from './compiler';
const virtualFileLoader = require.resolve(
path.join(
path.dirname(require.resolve('../../package.json')),
'virtualFileLoader',
),
);
const virtualFileLoaderExtractionFile = path.join(
path.dirname(require.resolve('../../package.json')),
'extracted.js',
);
const virtualNextFileLoaderExtractionFile = path.join(
path.dirname(require.resolve('../../package.json')),
'vanilla.virtual.css',
);
interface LoaderOptions {
outputCss: boolean;
identifiers?: IdentifierOption;
}
interface InternalLoaderOptions extends LoaderOptions {
childCompiler: ChildCompiler;
virtualLoader: 'virtualFileLoader' | 'virtualNextFileLoader';
}
const defaultIdentifierOption = (
mode: LoaderContext['mode'],
identifiers?: IdentifierOption,
): IdentifierOption =>
identifiers ?? (mode === 'production' ? 'short' : 'debug');
export default function (this: LoaderContext, source: string) {
const { identifiers } = loaderUtils.getOptions(this) as InternalLoaderOptions;
const { name } = getPackageInfo(this.rootContext);
const callback = this.async();
transform({
source,
filePath: this.resourcePath,
rootPath: this.rootContext,
packageName: name,
identOption: defaultIdentifierOption(this.mode, identifiers),
})
.then((code) => {
callback(null, code);
})
.catch((e) => {
callback(e);
});
}
export function pitch(this: LoaderContext) {
const { childCompiler, outputCss, identifiers, virtualLoader } =
loaderUtils.getOptions(this) as InternalLoaderOptions;
const log = debug(
`vanilla-extract:loader:${formatResourcePath(this.resourcePath)}`,
);
const compiler = this._compiler;
const isChildCompiler = childCompiler.isChildCompiler(compiler.name);
if (isChildCompiler) {
log(
'Skip vanilla-extract loader as we are already within a child compiler for %s',
compiler.options.output.filename,
);
return;
}
log('Loading file');
const callback = this.async();
childCompiler
.getCompiledSource(this)
.then(async ({ source }) => {
const result = await processVanillaFile({
source,
outputCss,
filePath: this.resourcePath,
identOption: defaultIdentifierOption(this.mode, identifiers),
serializeVirtualCssPath: async ({ fileName, source }) => {
const serializedCss = await serializeCss(source);
if (virtualLoader === 'virtualFileLoader') {
const virtualResourceLoader = `${virtualFileLoader}?${JSON.stringify(
{
fileName,
source: serializedCss,
},
)}`;
const request = loaderUtils.stringifyRequest(
this,
`${fileName}!=!${virtualResourceLoader}!${virtualFileLoaderExtractionFile}`,
);
return `import ${request}`;
} else {
// https://github.com/SukkaW/style9-webpack/blob/f51c46bbcd95ea3b988d3559c3b35cc056874366/src/next-appdir/style9-next-loader.ts#L64-L72
const request = loaderUtils.stringifyRequest(
this,
// Next.js RSC CSS extraction will discard any loaders in the request.
// So we need to pass virtual css information through resourceQuery.
// https://github.com/vercel/next.js/blob/3a9bfe60d228fc2fd8fe65b76d49a0d21df4ecc7/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts#L425-L429
// The compressed serialized CSS of vanilla-extract will add compressionFlag.
// Causing the resourceQuery to be abnormally split, so uri encoding is required.
// https://github.com/vanilla-extract-css/vanilla-extract/blob/58005eb5e7456cf2b3c04ea7aef29677db37cc3c/packages/integration/src/serialize.ts#L15
`${virtualNextFileLoaderExtractionFile}?${encodeURIComponent(
JSON.stringify({ fileName, source: serializedCss }),
)}`,
);
return `import ${request}`;
}
},
});
log('Completed successfully');
callback(null, result);
})
.catch((e) => {
callback(e);
});
}