stylex-webpack 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -3
- package/dist/index.js +103 -85
- package/dist/next.js +19 -6
- package/dist/stylex-loader.js +16 -25
- package/dist/{stylex-fuck-nextjs-virtual-carrier-loader.js → stylex-virtual-css-loader.js} +9 -7
- package/dist/stylex-virtual.css +7 -0
- package/package.json +22 -24
- package/dist/stylex.fuck-nextjs.virtual-carrier.css +0 -15
package/dist/index.d.ts
CHANGED
|
@@ -49,16 +49,14 @@ interface StyleXPluginOption {
|
|
|
49
49
|
*/
|
|
50
50
|
transformCss?: CSSTransformer;
|
|
51
51
|
}
|
|
52
|
-
type RegisterStyleXRules = (resourcePath: string, stylexRules: Rule[]) => void;
|
|
53
52
|
declare class StyleXPlugin {
|
|
54
53
|
stylexRules: Map<string, readonly Rule[]>;
|
|
55
54
|
useCSSLayers: boolean;
|
|
56
55
|
loaderOption: StyleXLoaderOptions;
|
|
57
56
|
transformCss: CSSTransformer;
|
|
58
|
-
private readonly _virtualModuleInstance;
|
|
59
57
|
constructor({ stylexImports, useCSSLayers, stylexOption, nextjsMode, nextjsAppRouterMode, transformCss }?: StyleXPluginOption);
|
|
60
58
|
apply(compiler: webpack.Compiler): void;
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
export { StyleXPlugin };
|
|
64
|
-
export type {
|
|
62
|
+
export type { StyleXPluginOption };
|
package/dist/index.js
CHANGED
|
@@ -3,19 +3,28 @@
|
|
|
3
3
|
var stylexBabelPlugin = require('@stylexjs/babel-plugin');
|
|
4
4
|
var path = require('node:path');
|
|
5
5
|
var process = require('node:process');
|
|
6
|
-
var VirtualModulesPlugin = require('webpack-virtual-modules');
|
|
7
6
|
var identity = require('foxts/identity');
|
|
8
7
|
|
|
9
|
-
var version = "0.4.
|
|
8
|
+
var version = "0.4.5";
|
|
10
9
|
|
|
11
10
|
const PLUGIN_NAME = 'stylex';
|
|
12
11
|
const VIRTUAL_ENTRYPOINT_CSS_PATH = require.resolve('./stylex.css');
|
|
13
|
-
|
|
12
|
+
require.resolve('./stylex-virtual.css');
|
|
13
|
+
const VIRTUAL_CSS_PATTERN = /stylex\.css|stylex-virtual\.css/;
|
|
14
|
+
const VIRTUAL_STYLEX_CSS_DUMMY_IMPORT_PATTERN = /stylex-virtual\.css/;
|
|
14
15
|
const STYLEX_CHUNK_NAME = '_stylex-webpack-generated';
|
|
15
|
-
require.resolve('./stylex.fuck-nextjs.virtual-carrier.css');
|
|
16
|
-
const FUCK_NEXTJS_VIRTUAL_CARRIER_PATTERN = /stylex\.fuck-nextjs\.virtual-carrier\.css/;
|
|
17
|
-
const FUCK_NEXTJS_VIRTUAL_CARRIERCHUNK_NAME = '_stylex-fuck-nextjs-collect-stylex-rules';
|
|
18
16
|
const INCLUDE_REGEXP = /\.[cm]?[jt]sx?$/;
|
|
17
|
+
const BUILD_INFO_STYLEX_KEY = '~stylex_webpack_stylex_rules';
|
|
18
|
+
// https://github.com/vercel/next.js/blob/ad6907a8a37e930639af071203f4ce49a5d69ee5/packages/next/src/shared/lib/constants.ts#L7
|
|
19
|
+
const NEXTJS_COMPILER_NAMES = {
|
|
20
|
+
client: 'client',
|
|
21
|
+
server: 'server',
|
|
22
|
+
edgeServer: 'edge-server'
|
|
23
|
+
};
|
|
24
|
+
function isNextJsCompilerName(name) {
|
|
25
|
+
if (name == null) return false;
|
|
26
|
+
return NEXTJS_COMPILER_NAMES[name] === name;
|
|
27
|
+
}
|
|
19
28
|
|
|
20
29
|
function _define_property(obj, key, value) {
|
|
21
30
|
if (key in obj) {
|
|
@@ -31,7 +40,7 @@ function _define_property(obj, key, value) {
|
|
|
31
40
|
return obj;
|
|
32
41
|
}
|
|
33
42
|
const stylexLoaderPath = require.resolve('./stylex-loader');
|
|
34
|
-
const
|
|
43
|
+
const stylexVirtualCssLoaderPath = require.resolve('./stylex-virtual-css-loader');
|
|
35
44
|
function getStyleXRules(stylexRules, useCSSLayers) {
|
|
36
45
|
if (stylexRules.size === 0) {
|
|
37
46
|
return null;
|
|
@@ -50,24 +59,14 @@ class StyleXPlugin {
|
|
|
50
59
|
'"optimization.splitChunks" should be enabled for "stylex-webpack" to function properly.'
|
|
51
60
|
].join(' '));
|
|
52
61
|
}
|
|
53
|
-
this._virtualModuleInstance.apply(compiler);
|
|
54
62
|
(_compiler_options_optimization_splitChunks = compiler.options.optimization.splitChunks).cacheGroups ?? (_compiler_options_optimization_splitChunks.cacheGroups = {});
|
|
55
63
|
compiler.options.optimization.splitChunks.cacheGroups[STYLEX_CHUNK_NAME] = {
|
|
56
64
|
name: STYLEX_CHUNK_NAME,
|
|
57
|
-
test:
|
|
65
|
+
test: VIRTUAL_CSS_PATTERN,
|
|
58
66
|
type: 'css/mini-extract',
|
|
59
67
|
chunks: 'all',
|
|
60
68
|
enforce: true
|
|
61
69
|
};
|
|
62
|
-
if (this.loaderOption.nextjsMode) {
|
|
63
|
-
compiler.options.optimization.splitChunks.cacheGroups[FUCK_NEXTJS_VIRTUAL_CARRIERCHUNK_NAME] = {
|
|
64
|
-
name: FUCK_NEXTJS_VIRTUAL_CARRIERCHUNK_NAME,
|
|
65
|
-
test: FUCK_NEXTJS_VIRTUAL_CARRIER_PATTERN,
|
|
66
|
-
type: 'css/mini-extract',
|
|
67
|
-
chunks: 'all',
|
|
68
|
-
enforce: true
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
70
|
// const IS_RSPACK = Object.prototype.hasOwnProperty.call(compiler.webpack, 'rspackVersion');
|
|
72
71
|
// stylex-loader adds virtual css import (which triggers virtual-loader)
|
|
73
72
|
// This prevents "stylex.virtual.css" files from being tree shaken by forcing
|
|
@@ -83,6 +82,12 @@ class StyleXPlugin {
|
|
|
83
82
|
}
|
|
84
83
|
});
|
|
85
84
|
});
|
|
85
|
+
// compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
86
|
+
// compilation.dependencyTemplates.set(
|
|
87
|
+
// CssLocalIdentifierDependency,
|
|
88
|
+
// new CssLocalIdentifierDependency.Template()
|
|
89
|
+
// );
|
|
90
|
+
// });
|
|
86
91
|
const { Compilation, NormalModule, sources } = compiler.webpack;
|
|
87
92
|
const { RawSource } = sources;
|
|
88
93
|
const meta = JSON.stringify({
|
|
@@ -90,25 +95,14 @@ class StyleXPlugin {
|
|
|
90
95
|
packageVersion: version,
|
|
91
96
|
opt: this.loaderOption
|
|
92
97
|
});
|
|
98
|
+
const logger = compiler.getInfrastructureLogger(PLUGIN_NAME);
|
|
93
99
|
// Apply loader to JS modules
|
|
94
100
|
compiler.hooks.make.tap(PLUGIN_NAME, (compilation)=>{
|
|
95
101
|
compilation.hooks.chunkHash.tap(PLUGIN_NAME, (_, hash)=>hash.update(meta));
|
|
96
|
-
NormalModule.getCompilationHooks(compilation).loader.tap(PLUGIN_NAME, (
|
|
102
|
+
NormalModule.getCompilationHooks(compilation).loader.tap(PLUGIN_NAME, (_loaderContext, mod)=>{
|
|
97
103
|
const extname = path.extname(mod.matchResource || mod.resource);
|
|
98
|
-
|
|
99
|
-
mod.loaders.push({
|
|
100
|
-
loader: fuckNextjsVirtualLoaderPath,
|
|
101
|
-
options: {},
|
|
102
|
-
ident: null,
|
|
103
|
-
type: null
|
|
104
|
-
});
|
|
105
|
-
}
|
|
104
|
+
logger.debug(`attaching stylex-loader to ${mod.matchResource || mod.resource}`);
|
|
106
105
|
if (INCLUDE_REGEXP.test(extname)) {
|
|
107
|
-
loaderContext.StyleXWebpackContextKey = {
|
|
108
|
-
registerStyleXRules: (resourcePath, stylexRules)=>{
|
|
109
|
-
this.stylexRules.set(resourcePath, stylexRules);
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
106
|
// We use .push() here instead of .unshift()
|
|
113
107
|
// Webpack usually runs loaders in reverse order and we want to ideally run
|
|
114
108
|
// our loader before anything else.
|
|
@@ -118,45 +112,78 @@ class StyleXPlugin {
|
|
|
118
112
|
ident: null,
|
|
119
113
|
type: null
|
|
120
114
|
});
|
|
115
|
+
} else if (VIRTUAL_STYLEX_CSS_DUMMY_IMPORT_PATTERN.test(mod.matchResource || mod.resource)) {
|
|
116
|
+
mod.loaders.push({
|
|
117
|
+
loader: stylexVirtualCssLoaderPath,
|
|
118
|
+
ident: null,
|
|
119
|
+
type: null
|
|
120
|
+
});
|
|
121
121
|
}
|
|
122
122
|
});
|
|
123
123
|
compilation.hooks.processAssets.tapPromise({
|
|
124
124
|
name: PLUGIN_NAME,
|
|
125
125
|
stage: Compilation.PROCESS_ASSETS_STAGE_PRE_PROCESS
|
|
126
126
|
}, async (assets)=>{
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (fuckNextjsChunk) {
|
|
134
|
-
const cssModulesInFuckNextjsChunk = compilation.chunkGraph.getChunkModulesIterableBySourceType(fuckNextjsChunk, 'css/mini-extract');
|
|
135
|
-
// we only re-collect stylex rules if we can found css in the stylex chunk
|
|
136
|
-
if (cssModulesInFuckNextjsChunk) {
|
|
137
|
-
for (const cssModule of cssModulesInFuckNextjsChunk){
|
|
138
|
-
if (!('_identifier' in cssModule) || typeof cssModule._identifier !== 'string') {
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
const stringifiedStylexRule = cssModule._identifier.split('!').pop()?.split('?').pop();
|
|
142
|
-
if (!stringifiedStylexRule) {
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
const params = new URLSearchParams(stringifiedStylexRule);
|
|
146
|
-
const stylex = params.get('stylex');
|
|
147
|
-
const from = params.get('from');
|
|
148
|
-
if (stylex != null && from != null) {
|
|
149
|
-
this.stylexRules.set(from, JSON.parse(stylex));
|
|
150
|
-
}
|
|
151
|
-
}
|
|
127
|
+
compilation.modules.forEach((mod)=>{
|
|
128
|
+
if (mod.buildInfo && BUILD_INFO_STYLEX_KEY in mod.buildInfo) {
|
|
129
|
+
const stylexBuildInfo = mod.buildInfo[BUILD_INFO_STYLEX_KEY];
|
|
130
|
+
if (typeof stylexBuildInfo === 'object' && stylexBuildInfo != null && 'resourcePath' in stylexBuildInfo && 'stylexRules' in stylexBuildInfo && typeof stylexBuildInfo.resourcePath === 'string') {
|
|
131
|
+
logger.debug(`collecting stylex rules from ${stylexBuildInfo.resourcePath}'s build info`);
|
|
132
|
+
this.stylexRules.set(stylexBuildInfo.resourcePath, stylexBuildInfo.stylexRules);
|
|
152
133
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
if (this.loaderOption.nextjsMode && this.loaderOption.nextjsAppRouterMode && isNextJsCompilerName(compiler.name)) {
|
|
137
|
+
/**
|
|
138
|
+
* Next.js call webpack compiler through "runCompiler": https://github.com/vercel/next.js/blob/c0c75e4aaa8ece2c9e789e2e3f150d7487b60bbc/packages/next/src/build/compiler.ts#L39
|
|
139
|
+
*
|
|
140
|
+
* The "runCompiler" funtion is invoked by "webpackBuildImpl" function: https://github.com/vercel/next.js/blob/ad6907a8a37e930639af071203f4ce49a5d69ee5/packages/next/src/build/webpack-build/impl.ts#L203
|
|
141
|
+
*
|
|
142
|
+
* The "webpackBuildImpl" function accepts "compilerName" parameter, and is invoked by "webpackBuild" function: https://github.com/vercel/next.js/blob/c0c75e4aaa8ece2c9e789e2e3f150d7487b60bbc/packages/next/src/build/webpack-build/index.ts#L124
|
|
143
|
+
* When build worker is enabled, the "compilerName" parameter is set to either "client", "server" or "edge-server". If build worker is disabled,
|
|
144
|
+
* the "compilerName" parameter is always "null".
|
|
145
|
+
*
|
|
146
|
+
* When build worker is disabled, the multi-stage build is managed by "webpackBuildImpl" function itself: https://github.com/vercel/next.js/blob/ad6907a8a37e930639af071203f4ce49a5d69ee5/packages/next/src/build/webpack-build/impl.ts#L203
|
|
147
|
+
* It will first run "server" compiler, then "edge-server" compiler, and finally "client" compiler.
|
|
148
|
+
*
|
|
149
|
+
* The "webpackBuildImpl" function is invoked by "webpackBuild" function: https://github.com/vercel/next.js/blob/c0c75e4aaa8ece2c9e789e2e3f150d7487b60bbc/packages/next/src/build/webpack-build/index.ts#L124
|
|
150
|
+
*
|
|
151
|
+
* If build worker is enabled, the multi-stage build is managed by the build entrypoint, and the "client", "server" and "edge-server" compilerName
|
|
152
|
+
* is passed to "webpackBuildImpl" through "webpackBuild" function:
|
|
153
|
+
* https://github.com/vercel/next.js/blob/c0c75e4aaa8ece2c9e789e2e3f150d7487b60bbc/packages/next/src/build/index.ts#L905
|
|
154
|
+
* https://github.com/vercel/next.js/blob/c0c75e4aaa8ece2c9e789e2e3f150d7487b60bbc/packages/next/src/build/index.ts#L1796
|
|
155
|
+
*
|
|
156
|
+
* Note that, if a custom webpack config is provided, Next.js will always disable build worker: https://github.com/vercel/next.js/blob/c0c75e4aaa8ece2c9e789e2e3f150d7487b60bbc/packages/next/src/build/index.ts#L1723
|
|
157
|
+
* We will not take that as an assumption. We already overwrite "nextConfig.experimental.webpackBuildWorker" to false in the Next.js plugin.
|
|
158
|
+
*
|
|
159
|
+
* Now all compiler instances are running in the same process, we can use a global variable to track stylex rules from different compilers.
|
|
160
|
+
*
|
|
161
|
+
* Back to "runCompiler". "runCompiler" accepts webpack configurations which is created by "getBaseWebpackConfig" function: https://github.com/vercel/next.js/blob/ad6907a8a37e930639af071203f4ce49a5d69ee5/packages/next/src/build/webpack-build/impl.ts#L128
|
|
162
|
+
*
|
|
163
|
+
* Inside "getBaseWebpackConfig" function, there is a "buildConfiguration" function: https://github.com/vercel/next.js/blob/ad6907a8a37e930639af071203f4ce49a5d69ee5/packages/next/src/build/webpack-config.ts#L2464
|
|
164
|
+
* Inside "buildConfiguration" function there is a curried "base" function: https://github.com/vercel/next.js/blob/c0c75e4aaa8ece2c9e789e2e3f150d7487b60bbc/packages/next/src/build/webpack/config/index.ts#L73
|
|
165
|
+
* Inside the "base" function, the compiler name is attached to the webpack configuration: https://github.com/vercel/next.js/blob/c0c75e4aaa8ece2c9e789e2e3f150d7487b60bbc/packages/next/src/build/webpack/config/blocks/base.ts#L24
|
|
166
|
+
*/ if (compiler.name === NEXTJS_COMPILER_NAMES.server || compiler.name === NEXTJS_COMPILER_NAMES.edgeServer) {
|
|
167
|
+
var _globalThis;
|
|
168
|
+
((_globalThis = globalThis).__stylex_nextjs_global_registry__ ?? (_globalThis.__stylex_nextjs_global_registry__ = new Map())).set(compiler.name, this.stylexRules);
|
|
169
|
+
// we don't need to do anything more in server/edge compiler, no CSS generation is needed
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- type safe
|
|
173
|
+
if (compiler.name === NEXTJS_COMPILER_NAMES.client) {
|
|
174
|
+
const globalRegistry = globalThis.__stylex_nextjs_global_registry__;
|
|
175
|
+
if (globalRegistry != null) {
|
|
176
|
+
// now we merge all collected rules from other compilers
|
|
177
|
+
globalRegistry.forEach((rules)=>{
|
|
178
|
+
rules.forEach((rule, resourcePath)=>{
|
|
179
|
+
if (!this.stylexRules.has(resourcePath)) {
|
|
180
|
+
this.stylexRules.set(resourcePath, rule);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
});
|
|
159
184
|
}
|
|
185
|
+
} else {
|
|
186
|
+
compiler.name;
|
|
160
187
|
}
|
|
161
188
|
}
|
|
162
189
|
const stylexCSS = getStyleXRules(this.stylexRules, this.useCSSLayers);
|
|
@@ -164,28 +191,20 @@ class StyleXPlugin {
|
|
|
164
191
|
return;
|
|
165
192
|
}
|
|
166
193
|
const finalCss = await this.transformCss(stylexCSS);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
// Let's find the css file that belongs to the stylex chunk
|
|
177
|
-
const stylexChunkCssAssetNames = Object.keys(assets).filter((assetName)=>stylexChunk.files.has(assetName) && assetName.endsWith('.css'));
|
|
178
|
-
if (stylexChunkCssAssetNames.length === 0) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
if (stylexChunkCssAssetNames.length > 1) {
|
|
182
|
-
console.warn('[stylex-webpack] Multiple CSS assets found for the stylex chunk. This should not happen. Please report this issue.');
|
|
183
|
-
}
|
|
184
|
-
const stylexAssetName = stylexChunkCssAssetNames[0];
|
|
185
|
-
compilation.updateAsset(stylexAssetName, ()=>new RawSource(finalCss), {
|
|
186
|
-
minimized: false
|
|
187
|
-
});
|
|
194
|
+
const stylexChunk = compilation.namedChunks.get(STYLEX_CHUNK_NAME);
|
|
195
|
+
if (!stylexChunk) return;
|
|
196
|
+
// Let's find the css file that belongs to the stylex chunk
|
|
197
|
+
const stylexChunkCssAssetNames = Object.keys(assets).filter((assetName)=>stylexChunk.files.has(assetName) && assetName.endsWith('.css'));
|
|
198
|
+
if (stylexChunkCssAssetNames.length === 0) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (stylexChunkCssAssetNames.length > 1) {
|
|
202
|
+
logger.warn('Multiple CSS assets found for the stylex chunk. This should not happen. Please report this issue.');
|
|
188
203
|
}
|
|
204
|
+
const stylexAssetName = stylexChunkCssAssetNames[0];
|
|
205
|
+
compilation.updateAsset(stylexAssetName, ()=>new RawSource(finalCss), {
|
|
206
|
+
minimized: false
|
|
207
|
+
});
|
|
189
208
|
});
|
|
190
209
|
});
|
|
191
210
|
}
|
|
@@ -197,7 +216,6 @@ class StyleXPlugin {
|
|
|
197
216
|
_define_property(this, "useCSSLayers", void 0);
|
|
198
217
|
_define_property(this, "loaderOption", void 0);
|
|
199
218
|
_define_property(this, "transformCss", void 0);
|
|
200
|
-
_define_property(this, "_virtualModuleInstance", new VirtualModulesPlugin());
|
|
201
219
|
this.useCSSLayers = useCSSLayers;
|
|
202
220
|
this.loaderOption = {
|
|
203
221
|
stylexImports,
|
package/dist/next.js
CHANGED
|
@@ -7,8 +7,8 @@ var css = require('next/dist/build/webpack/config/blocks/css');
|
|
|
7
7
|
var index = require('./index');
|
|
8
8
|
|
|
9
9
|
require.resolve('./stylex.css');
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
require.resolve('./stylex-virtual.css');
|
|
11
|
+
const VIRTUAL_CSS_PATTERN = /stylex\.css|stylex-virtual\.css/;
|
|
12
12
|
|
|
13
13
|
/** Next.js' precompilation add "__esModule: true", but doesn't add an actual default exports */ // @ts-expect-error -- Next.js fucks something up
|
|
14
14
|
const NextMiniCssExtractPlugin = nextMiniCssExtractPluginExports.default;
|
|
@@ -74,7 +74,8 @@ function getStyleXVirtualCssLoader(ctx, MiniCssExtractPlugin, postcss) {
|
|
|
74
74
|
return loaders;
|
|
75
75
|
}
|
|
76
76
|
function withStyleX(pluginOptions) {
|
|
77
|
-
return (nextConfig = {})=>
|
|
77
|
+
return (nextConfig = {})=>{
|
|
78
|
+
const config = {
|
|
78
79
|
...nextConfig,
|
|
79
80
|
webpack (config, ctx) {
|
|
80
81
|
var // For some reason, Next 11.0.1 has `config.optimization.splitChunks`
|
|
@@ -98,7 +99,7 @@ function withStyleX(pluginOptions) {
|
|
|
98
99
|
const cssRules = (config.module?.rules?.find((rule)=>typeof rule === 'object' && rule !== null && Array.isArray(rule.oneOf) && rule.oneOf.some((setRule)=>setRule && setRule.test instanceof RegExp && typeof setRule.test.test === 'function' && setRule.test.test('filename.css')))).oneOf;
|
|
99
100
|
// Here we matches virtual css file emitted by StyleXPlugin
|
|
100
101
|
cssRules?.unshift({
|
|
101
|
-
test:
|
|
102
|
+
test: VIRTUAL_CSS_PATTERN,
|
|
102
103
|
use: getStyleXVirtualCssLoader(ctx, MiniCssExtractPlugin, postcss)
|
|
103
104
|
});
|
|
104
105
|
(_config1 = config).plugins ?? (_config1.plugins = []);
|
|
@@ -147,7 +148,10 @@ function withStyleX(pluginOptions) {
|
|
|
147
148
|
},
|
|
148
149
|
async transformCss (css) {
|
|
149
150
|
const { postcssWithPlugins } = await postcss();
|
|
150
|
-
|
|
151
|
+
// add from: undefined to avoid source map warning
|
|
152
|
+
const result = await postcssWithPlugins.process(css, {
|
|
153
|
+
from: undefined
|
|
154
|
+
});
|
|
151
155
|
if (pluginOptions?.transformCss) {
|
|
152
156
|
return pluginOptions.transformCss(result.css);
|
|
153
157
|
}
|
|
@@ -156,7 +160,16 @@ function withStyleX(pluginOptions) {
|
|
|
156
160
|
}));
|
|
157
161
|
return config;
|
|
158
162
|
}
|
|
159
|
-
}
|
|
163
|
+
};
|
|
164
|
+
// https://github.com/vercel/next.js/blob/ad6907a8a37e930639af071203f4ce49a5d69ee5/packages/next/src/build/index.ts#L1723
|
|
165
|
+
// Actually, if a custom webpack config is provided, Next.js will always disable parallel bundling
|
|
166
|
+
// But we should not take that as an assumption, so we just warn and disable the options
|
|
167
|
+
if (config.experimental?.webpackBuildWorker) {
|
|
168
|
+
log.warn('[stylex-webpack] "experimental.webpackBuildWorker" is not supported with "stylex-webpack", the option will be disabled.');
|
|
169
|
+
config.experimental.webpackBuildWorker = false;
|
|
170
|
+
}
|
|
171
|
+
return config;
|
|
172
|
+
};
|
|
160
173
|
}
|
|
161
174
|
|
|
162
175
|
exports.withStyleX = withStyleX;
|
package/dist/stylex-loader.js
CHANGED
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@babel/core');
|
|
4
4
|
var stylexBabelPlugin = require('@stylexjs/babel-plugin');
|
|
5
|
+
var guard = require('foxts/guard');
|
|
5
6
|
|
|
6
7
|
require.resolve('./stylex.css');
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
// eslint-disable-next-line prefer-object-has-own -- target older
|
|
10
|
-
return Object.prototype.hasOwnProperty.call(context, 'StyleXWebpackContextKey');
|
|
11
|
-
}
|
|
8
|
+
const VIRTUAL_STYLEX_CSS_DUMMY_IMPORT_PATH = require.resolve('./stylex-virtual.css');
|
|
9
|
+
const BUILD_INFO_STYLEX_KEY = '~stylex_webpack_stylex_rules';
|
|
12
10
|
|
|
13
11
|
function stringifyRequest(loaderContext, request) {
|
|
14
12
|
return JSON.stringify(loaderContext.utils.contextify(loaderContext.context || loaderContext.rootContext, request));
|
|
@@ -17,14 +15,11 @@ function stringifyRequest(loaderContext, request) {
|
|
|
17
15
|
const PLUGIN_NAME = 'stylex';
|
|
18
16
|
async function stylexLoader(inputCode, inputSourceMap) {
|
|
19
17
|
const callback = this.async();
|
|
20
|
-
const { stylexImports, stylexOption
|
|
18
|
+
const { stylexImports, stylexOption } = this.getOptions();
|
|
21
19
|
// bail out early if the input doesn't contain stylex imports
|
|
22
20
|
if (!stylexImports.some((importName)=>inputCode.includes(importName))) {
|
|
23
21
|
return callback(null, inputCode, inputSourceMap);
|
|
24
22
|
}
|
|
25
|
-
if (!isSupplementedLoaderContext(this)) {
|
|
26
|
-
return callback(new Error('stylex-loader: loader context is not SupplementedLoaderContext!'));
|
|
27
|
-
}
|
|
28
23
|
try {
|
|
29
24
|
const { code, map, metadata } = await core.transformAsync(inputCode, {
|
|
30
25
|
babelrc: false,
|
|
@@ -51,22 +46,18 @@ async function stylexLoader(inputCode, inputSourceMap) {
|
|
|
51
46
|
}
|
|
52
47
|
// this.stylexRules[filename] = metadata.stylex;
|
|
53
48
|
logger?.debug(`Read stylex styles from ${this.resourcePath}:`, metadata.stylex);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const postfix = `\nimport ${virtualCssRequest};`;
|
|
67
|
-
return callback(null, code + postfix, map ?? undefined);
|
|
68
|
-
}
|
|
69
|
-
return callback(null, code ?? undefined, map ?? undefined);
|
|
49
|
+
guard.nullthrow(this._module?.buildInfo, '[stylex-webpack] Expected "this._module.buildInfo" to be defined')[BUILD_INFO_STYLEX_KEY] = {
|
|
50
|
+
resourcePath: this.resourcePath,
|
|
51
|
+
stylexRules: metadata.stylex
|
|
52
|
+
};
|
|
53
|
+
// Add a dummy virtual import that will be picked up by virtual dummy import loader to add fake CSS to invalidate HMR
|
|
54
|
+
const urlParams = new URLSearchParams({
|
|
55
|
+
from: this.resourcePath,
|
|
56
|
+
stylex: JSON.stringify(metadata.stylex) // color: #fff is not url safe, let's get through JSON.stringify
|
|
57
|
+
});
|
|
58
|
+
const virtualCssRequest = stringifyRequest(this, `${VIRTUAL_STYLEX_CSS_DUMMY_IMPORT_PATH}?${urlParams.toString()}`);
|
|
59
|
+
const postfix = `\nimport ${virtualCssRequest};`;
|
|
60
|
+
return callback(null, code + postfix, map ?? undefined);
|
|
70
61
|
} catch (error) {
|
|
71
62
|
return callback(error);
|
|
72
63
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var loaderUtils = require('loader-utils');
|
|
4
|
-
var tsDedent = require('ts-dedent');
|
|
5
4
|
|
|
6
5
|
// prefer loader-utils over self-implemented hash function to utilize caching + bulk hashing
|
|
7
|
-
function
|
|
6
|
+
function stylexVirtualCssLoader(inputCode, inputSourceMap) {
|
|
8
7
|
const callback = this.async();
|
|
8
|
+
this.cacheable(false);
|
|
9
|
+
if (this._compiler?.options.mode === 'production') {
|
|
10
|
+
// In development mode, we don't need to generate the virtual CSS content
|
|
11
|
+
callback(null, inputCode, inputSourceMap);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
9
14
|
const data = new URLSearchParams(this.resourceQuery.slice(1));
|
|
10
15
|
try {
|
|
11
16
|
const stylex = data.get('stylex');
|
|
@@ -15,14 +20,11 @@ function stylexFuckNextjsVirtualCarrierLoader(inputCode, inputSourceMap) {
|
|
|
15
20
|
}
|
|
16
21
|
// @ts-expect-error -- getHashDigest supports string & xxhash64
|
|
17
22
|
const hash = loaderUtils.getHashDigest(stylex, 'xxhash64', 'base62', 32);
|
|
18
|
-
const code =
|
|
19
|
-
/** stylex rules: ${stylex} */
|
|
20
|
-
.stylex-fuck-nextjs-${hash} {}
|
|
21
|
-
`;
|
|
23
|
+
const code = `/** stylex rules: ${stylex} */\n.stylex-hashed-${hash} {}`;
|
|
22
24
|
callback(null, inputCode + '\n' + code);
|
|
23
25
|
} catch (e) {
|
|
24
26
|
callback(e);
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
module.exports =
|
|
30
|
+
module.exports = stylexVirtualCssLoader;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a noop file that is meant to be imported via a dummy import by stylex webpack loader
|
|
3
|
+
*
|
|
4
|
+
* This has to be an actual file as webpack requires a file to exist on disk
|
|
5
|
+
*
|
|
6
|
+
* In production build this should have been minimized away, if not please report an issue.
|
|
7
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stylex-webpack",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "The another Webpack Plugin for Facebook's StyleX",
|
|
5
5
|
"homepage": "https://github.com/SukkaW/style9-webpack#readme",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"./stylex.css": "./dist/stylex.css"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
|
-
"prebuild": "
|
|
32
|
+
"prebuild": "premove dist",
|
|
33
33
|
"build": "rollup -c rollup.config.ts --configPlugin swc3 --bundleConfigAsCjs",
|
|
34
34
|
"lint": "eslint --format=sukka .",
|
|
35
35
|
"test": "mocha --require @swc-node/register --require mocha-expect-snapshot test/index.ts",
|
|
@@ -49,50 +49,48 @@
|
|
|
49
49
|
"author": "Sukka <https://skk.moe>",
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@babel/core": "^7.28.
|
|
52
|
+
"@babel/core": "^7.28.5",
|
|
53
53
|
"@babel/plugin-syntax-jsx": "^7.27.1",
|
|
54
54
|
"@babel/plugin-syntax-typescript": "^7.27.1",
|
|
55
55
|
"@types/webpack": "^5.28.5",
|
|
56
|
-
"foxts": "^
|
|
57
|
-
"loader-utils": "^3.3.1"
|
|
58
|
-
"ts-dedent": "^2.2.0",
|
|
59
|
-
"webpack-virtual-modules": "^0.6.2"
|
|
56
|
+
"foxts": "^5.0.0",
|
|
57
|
+
"loader-utils": "^3.3.1"
|
|
60
58
|
},
|
|
61
59
|
"devDependencies": {
|
|
62
|
-
"@eslint-sukka/node": "^
|
|
60
|
+
"@eslint-sukka/node": "^8.0.2",
|
|
63
61
|
"@rollup/plugin-json": "^6.1.0",
|
|
64
62
|
"@swc-node/register": "^1.11.1",
|
|
65
|
-
"@swc/core": "^1.
|
|
63
|
+
"@swc/core": "^1.15.0",
|
|
66
64
|
"@types/babel__core": "^7.20.5",
|
|
67
65
|
"@types/loader-utils": "^3.0.0",
|
|
68
66
|
"@types/mocha": "^10.0.10",
|
|
69
|
-
"@types/node": "^22.
|
|
70
|
-
"browserslist": "^4.
|
|
71
|
-
"bumpp": "^10.
|
|
67
|
+
"@types/node": "^22.19.0",
|
|
68
|
+
"browserslist": "^4.27.0",
|
|
69
|
+
"bumpp": "^10.3.1",
|
|
72
70
|
"css-loader": "^7.1.2",
|
|
73
|
-
"eslint": "^9.
|
|
74
|
-
"eslint-config-sukka": "^
|
|
75
|
-
"eslint-formatter-sukka": "^
|
|
76
|
-
"expect": "^30.
|
|
77
|
-
"memfs": "^4.
|
|
71
|
+
"eslint": "^9.39.1",
|
|
72
|
+
"eslint-config-sukka": "^8.0.2",
|
|
73
|
+
"eslint-formatter-sukka": "^8.0.2",
|
|
74
|
+
"expect": "^30.2.0",
|
|
75
|
+
"memfs": "^4.50.0",
|
|
78
76
|
"mini-css-extract-plugin": "^2.9.4",
|
|
79
|
-
"mocha": "^11.7.
|
|
77
|
+
"mocha": "^11.7.5",
|
|
80
78
|
"mocha-expect-snapshot": "^8.0.0",
|
|
81
|
-
"next": "^15.5.
|
|
79
|
+
"next": "^15.5.6",
|
|
82
80
|
"postcss": "^8.5.6",
|
|
83
|
-
"
|
|
84
|
-
"rollup": "^4.
|
|
81
|
+
"premove": "^4.0.0",
|
|
82
|
+
"rollup": "^4.52.5",
|
|
85
83
|
"rollup-plugin-copy": "^3.5.0",
|
|
86
84
|
"rollup-plugin-dts": "^6.2.3",
|
|
87
85
|
"rollup-plugin-swc3": "^0.12.1",
|
|
88
86
|
"swc-loader": "^0.2.6",
|
|
89
|
-
"typescript": "^5.9.
|
|
90
|
-
"webpack": "^5.
|
|
87
|
+
"typescript": "^5.9.3",
|
|
88
|
+
"webpack": "^5.102.1"
|
|
91
89
|
},
|
|
92
90
|
"peerDependencies": {
|
|
93
91
|
"@stylexjs/babel-plugin": "*"
|
|
94
92
|
},
|
|
95
|
-
"packageManager": "pnpm@10.
|
|
93
|
+
"packageManager": "pnpm@10.20.0",
|
|
96
94
|
"pnpm": {
|
|
97
95
|
"overrides": {
|
|
98
96
|
"eslint>chalk": "npm:picocolors@^1.1.1"
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This is a noop file specifically for Next.js app dir
|
|
3
|
-
*
|
|
4
|
-
* This has to be an actual file as webpack requires a file to exist on disk
|
|
5
|
-
*
|
|
6
|
-
* Due to how Next.js stupidly handles server code and client code in two different webpack namespaces,
|
|
7
|
-
* the client compiler instance can't have access to the server code, including styles registered in the server code.
|
|
8
|
-
*
|
|
9
|
-
* In order for the client bundle to collect all the styles, we use this virtual noop file as a bridge. This file doesn't
|
|
10
|
-
* do anything, but it will become a carrier, holding collected style rules. It is done by appending a fake import with
|
|
11
|
-
* a url query using the "stylex-loader".
|
|
12
|
-
*
|
|
13
|
-
* Later in webpack's "processAsset" phase, we collect these imports from chunk information, extract those url query from
|
|
14
|
-
* module identifiers, collect style rules for later CSS generation.
|
|
15
|
-
*/
|