@stylexjs/unplugin 0.17.0 → 0.17.2
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/README.md +97 -29
- package/lib/es/index.mjs +117 -8
- package/lib/index.d.ts +14 -1
- package/lib/index.js +117 -8
- package/package.json +3 -6
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# @stylexjs/unplugin
|
|
2
2
|
|
|
3
|
-
Universal bundler plugin for StyleX built on top of unplugin
|
|
3
|
+
Universal bundler plugin for StyleX built on top of `unplugin`. It compiles StyleX at build time, aggregates CSS from all transformed modules, and appends the result into an existing CSS asset produced by your bundler (or emits a stable fallback when none exists).
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
5
|
+
- Adapters for Vite/Rollup, Webpack/Rspack, and esbuild.
|
|
6
|
+
- Designed to keep StyleX output consolidated and deterministic.
|
|
7
|
+
- Dev helpers expose virtual modules for hot CSS reloads: `virtual:stylex:runtime` (JS) and `/virtual:stylex.css` (CSS) or `virtual:stylex:css-only` (JS shim).
|
|
7
8
|
|
|
8
9
|
## Install
|
|
9
10
|
|
|
@@ -11,56 +12,123 @@ Universal bundler plugin for StyleX built on top of unplugin. It compiles StyleX
|
|
|
11
12
|
npm i -D @stylexjs/unplugin
|
|
12
13
|
```
|
|
13
14
|
|
|
14
|
-
## Usage
|
|
15
|
+
## Usage by bundler
|
|
15
16
|
|
|
16
|
-
Vite
|
|
17
|
+
### Vite
|
|
17
18
|
|
|
18
|
-
```
|
|
19
|
+
```ts
|
|
19
20
|
// vite.config.ts
|
|
20
|
-
import { defineConfig } from 'vite'
|
|
21
|
-
import
|
|
21
|
+
import { defineConfig } from 'vite';
|
|
22
|
+
import react from '@vitejs/plugin-react';
|
|
23
|
+
import stylex from '@stylexjs/unplugin';
|
|
22
24
|
|
|
23
25
|
export default defineConfig({
|
|
24
|
-
plugins: [
|
|
25
|
-
|
|
26
|
+
plugins: [
|
|
27
|
+
// devMode: 'full' | 'css-only' | 'off'
|
|
28
|
+
// externalPackages: ['lib-using-stylex'] // optional manual include
|
|
29
|
+
stylex.vite(),
|
|
30
|
+
react(),
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Notes:
|
|
36
|
+
- The plugin auto-discovers installed packages that depend on `@stylexjs/stylex` (or any configured `importSources`) and excludes them from `optimizeDeps`/`ssr.optimizeDeps` so their StyleX code is transformed. Use `externalPackages` to force-deopt additional deps.
|
|
37
|
+
- `devMode: 'full'` injects a lightweight runtime that refetches the dev CSS endpoint on HMR. `css-only` serves just the CSS endpoint. `off` disables dev middleware/virtual modules.
|
|
38
|
+
- In dev, inject the virtual CSS + runtime from your HTML shell. If a `<script src="/@id/virtual:stylex:runtime">` tag is blocked by CORS (some frameworks proxy assets differently), call `import('virtual:stylex:runtime')` or `import('virtual:stylex:css-only')` from a tiny client shim instead.
|
|
39
|
+
- Ensure your app produces a CSS asset (default Vite behavior). If none exists, the plugin writes `stylex.css` in the output.
|
|
40
|
+
|
|
41
|
+
Dev HTML injection (baseline):
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<!-- Add in your HTML shell when import.meta.env.DEV -->
|
|
45
|
+
<link rel="stylesheet" href="/virtual:stylex.css" />
|
|
46
|
+
<script type="module">
|
|
47
|
+
import('virtual:stylex:runtime'); // or 'virtual:stylex:css-only' if you only need CSS
|
|
48
|
+
</script>
|
|
26
49
|
```
|
|
27
50
|
|
|
28
|
-
|
|
51
|
+
If your environment can safely load the runtime via a virtual module ID, replace
|
|
52
|
+
the inline script with `<script type="module" src="/@id/virtual:stylex:runtime">`.
|
|
53
|
+
|
|
54
|
+
### Rollup
|
|
29
55
|
|
|
30
56
|
```js
|
|
31
57
|
// rollup.config.mjs
|
|
32
|
-
import stylex from '@stylexjs/unplugin'
|
|
58
|
+
import stylex from '@stylexjs/unplugin';
|
|
33
59
|
|
|
34
60
|
export default {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
61
|
+
plugins: [stylex.rollup()],
|
|
62
|
+
};
|
|
38
63
|
```
|
|
39
64
|
|
|
40
|
-
Webpack
|
|
65
|
+
### Webpack
|
|
41
66
|
|
|
42
67
|
```js
|
|
43
68
|
// webpack.config.js
|
|
44
|
-
const stylex = require('@stylexjs/unplugin').default
|
|
69
|
+
const stylex = require('@stylexjs/unplugin').default;
|
|
70
|
+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
45
71
|
|
|
46
72
|
module.exports = {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
73
|
+
module: {
|
|
74
|
+
rules: [
|
|
75
|
+
// your JS/TS loader here
|
|
76
|
+
{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
plugins: [stylex.webpack({ useCSSLayers: true }), new MiniCssExtractPlugin()],
|
|
80
|
+
};
|
|
50
81
|
```
|
|
51
82
|
|
|
52
|
-
|
|
83
|
+
### Rspack
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
const rspack = require('@rspack/core');
|
|
87
|
+
const stylex = require('@stylexjs/unplugin').default;
|
|
53
88
|
|
|
54
|
-
|
|
89
|
+
module.exports = {
|
|
90
|
+
plugins: [
|
|
91
|
+
stylex.rspack(),
|
|
92
|
+
new rspack.CssExtractRspackPlugin({ filename: 'index.css' }),
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### esbuild
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
import esbuild from 'esbuild';
|
|
101
|
+
import stylex from '@stylexjs/unplugin';
|
|
102
|
+
|
|
103
|
+
esbuild.build({
|
|
104
|
+
entryPoints: ['src/App.jsx'],
|
|
105
|
+
bundle: true,
|
|
106
|
+
metafile: true, // lets the plugin locate CSS outputs if any
|
|
107
|
+
plugins: [
|
|
108
|
+
stylex.esbuild({
|
|
109
|
+
importSources: ['@stylexjs/stylex'],
|
|
110
|
+
useCSSLayers: true,
|
|
111
|
+
}),
|
|
112
|
+
],
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Options (shared)
|
|
117
|
+
|
|
118
|
+
- `dev`: boolean, defaults based on `NODE_ENV`/`BABEL_ENV`.
|
|
55
119
|
- `importSources`: array of import sources to scan, default `['stylex', '@stylexjs/stylex']`.
|
|
56
120
|
- `useCSSLayers`: boolean, emit CSS layers.
|
|
57
|
-
- `babelConfig`: `{ plugins, presets }` to merge.
|
|
58
|
-
- `unstable_moduleResolution`:
|
|
59
|
-
- `lightningcssOptions`: pass-through options for lightningcss
|
|
60
|
-
- `cssInjectionTarget`:
|
|
121
|
+
- `babelConfig`: `{ plugins, presets }` to merge into the internal Babel call.
|
|
122
|
+
- `unstable_moduleResolution`: forwarded to the StyleX Babel plugin.
|
|
123
|
+
- `lightningcssOptions`: pass-through options for `lightningcss`.
|
|
124
|
+
- `cssInjectionTarget`: `(fileName: string) => boolean` to pick a CSS asset to append to. Defaults to `index.css`, `style.css`, or the first `.css` asset.
|
|
125
|
+
- `externalPackages`: package names inside `node_modules` that should be treated like app code (useful if they ship StyleX). They are excluded from Vite dependency optimization.
|
|
126
|
+
- `devMode`: `'full' | 'css-only' | 'off'` (Vite only).
|
|
127
|
+
- `devPersistToDisk`: persist collected rules to `node_modules/.stylex/rules.json` in dev so multiple Vite environments can share CSS.
|
|
61
128
|
|
|
62
129
|
## Notes
|
|
63
130
|
|
|
64
|
-
-
|
|
65
|
-
- If the bundler
|
|
66
|
-
|
|
131
|
+
- With multiple outputs (e.g. client/SSR), each output gets its own aggregated StyleX CSS.
|
|
132
|
+
- If the bundler produces no CSS assets, the plugin emits a fallback `stylex.css` (often in `assets/` for Rollup/Vite or alongside esbuild outputs).
|
|
133
|
+
- When using extraction plugins (Webpack/Rspack), ensure they run so there is a CSS asset to append to; otherwise the fallback file is created.
|
|
134
|
+
- Dev HMR CSS hookup: add `<link rel="stylesheet" href="/virtual:stylex.css" />` to your shell in dev. For the JS runtime, prefer `import('virtual:stylex:runtime')` (or `virtual:stylex:css-only` if you only need CSS) from a local client shim when direct `<script src="/@id/virtual:stylex:runtime">` fails due to CORS/proxying.
|
package/lib/es/index.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import typescriptSyntaxPlugin from '@babel/plugin-syntax-typescript';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import fs from 'node:fs';
|
|
9
9
|
import fsp from 'node:fs/promises';
|
|
10
|
+
import { createRequire } from 'node:module';
|
|
10
11
|
import { transform as lightningTransform } from 'lightningcss';
|
|
11
12
|
import browserslist from 'browserslist';
|
|
12
13
|
import { browserslistToTargets } from 'lightningcss';
|
|
@@ -38,7 +39,84 @@ function processCollectedRulesToCSS(rules, options) {
|
|
|
38
39
|
});
|
|
39
40
|
return code.toString();
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
+
function readJSON(file) {
|
|
43
|
+
try {
|
|
44
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
45
|
+
return JSON.parse(content);
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function findNearestPackageJson(startDir) {
|
|
51
|
+
let dir = startDir;
|
|
52
|
+
for (;;) {
|
|
53
|
+
const candidate = path.join(dir, 'package.json');
|
|
54
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
55
|
+
const parent = path.dirname(dir);
|
|
56
|
+
if (parent === dir) break;
|
|
57
|
+
dir = parent;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function toPackageName(importSource) {
|
|
62
|
+
const source = typeof importSource === 'string' ? importSource : importSource?.from;
|
|
63
|
+
if (!source || source.startsWith('.') || source.startsWith('/')) return null;
|
|
64
|
+
if (source.startsWith('@')) {
|
|
65
|
+
const [scope, name] = source.split('/');
|
|
66
|
+
if (scope && name) return `${scope}/${name}`;
|
|
67
|
+
}
|
|
68
|
+
const [pkg] = source.split('/');
|
|
69
|
+
return pkg || null;
|
|
70
|
+
}
|
|
71
|
+
function hasStylexDependency(manifest, targetPackages) {
|
|
72
|
+
if (!manifest || typeof manifest !== 'object') return false;
|
|
73
|
+
const depFields = ['dependencies', 'peerDependencies', 'optionalDependencies'];
|
|
74
|
+
for (const field of depFields) {
|
|
75
|
+
const deps = manifest[field];
|
|
76
|
+
if (!deps || typeof deps !== 'object') continue;
|
|
77
|
+
for (const name of Object.keys(deps)) {
|
|
78
|
+
if (targetPackages.has(name)) return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
function discoverStylexPackages({
|
|
84
|
+
importSources,
|
|
85
|
+
explicitPackages,
|
|
86
|
+
rootDir,
|
|
87
|
+
resolver
|
|
88
|
+
}) {
|
|
89
|
+
const targetPackages = new Set(importSources.map(toPackageName).filter(Boolean).concat(['@stylexjs/stylex']));
|
|
90
|
+
const found = new Set(explicitPackages || []);
|
|
91
|
+
const pkgJsonPath = findNearestPackageJson(rootDir);
|
|
92
|
+
if (!pkgJsonPath) return Array.from(found);
|
|
93
|
+
const pkgDir = path.dirname(pkgJsonPath);
|
|
94
|
+
const pkgJson = readJSON(pkgJsonPath);
|
|
95
|
+
if (!pkgJson) return Array.from(found);
|
|
96
|
+
const depFields = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'];
|
|
97
|
+
const deps = new Set();
|
|
98
|
+
for (const field of depFields) {
|
|
99
|
+
const entries = pkgJson[field];
|
|
100
|
+
if (!entries || typeof entries !== 'object') continue;
|
|
101
|
+
for (const name of Object.keys(entries)) deps.add(name);
|
|
102
|
+
}
|
|
103
|
+
for (const dep of deps) {
|
|
104
|
+
let manifestPath = null;
|
|
105
|
+
try {
|
|
106
|
+
manifestPath = resolver.resolve(`${dep}/package.json`, {
|
|
107
|
+
paths: [pkgDir]
|
|
108
|
+
});
|
|
109
|
+
} catch {}
|
|
110
|
+
if (!manifestPath) continue;
|
|
111
|
+
const manifest = readJSON(manifestPath);
|
|
112
|
+
if (hasStylexDependency(manifest, targetPackages)) {
|
|
113
|
+
found.add(dep);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return Array.from(found);
|
|
117
|
+
}
|
|
118
|
+
const unpluginInstance = createUnplugin((userOptions = {}, metaOptions) => {
|
|
119
|
+
const framework = metaOptions?.framework;
|
|
42
120
|
const {
|
|
43
121
|
dev = process.env.NODE_ENV === 'development' || process.env.BABEL_ENV === 'development',
|
|
44
122
|
unstable_moduleResolution = {
|
|
@@ -53,8 +131,10 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
53
131
|
useCSSLayers = false,
|
|
54
132
|
lightningcssOptions,
|
|
55
133
|
cssInjectionTarget,
|
|
134
|
+
externalPackages = [],
|
|
56
135
|
devPersistToDisk = false,
|
|
57
136
|
devMode = 'full',
|
|
137
|
+
treeshakeCompensation = ['vite', 'rollup', 'rolldown'].includes(framework),
|
|
58
138
|
...stylexOptions
|
|
59
139
|
} = userOptions;
|
|
60
140
|
const stylexRulesById = new Map();
|
|
@@ -77,6 +157,14 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
77
157
|
}
|
|
78
158
|
let viteServer = null;
|
|
79
159
|
let viteOutDir = null;
|
|
160
|
+
const nearestPkgJson = findNearestPackageJson(process.cwd());
|
|
161
|
+
const requireFromCwd = nearestPkgJson ? createRequire(nearestPkgJson) : createRequire(path.join(process.cwd(), 'package.json'));
|
|
162
|
+
const stylexPackages = discoverStylexPackages({
|
|
163
|
+
importSources,
|
|
164
|
+
explicitPackages: externalPackages,
|
|
165
|
+
rootDir: nearestPkgJson ? path.dirname(nearestPkgJson) : process.cwd(),
|
|
166
|
+
resolver: requireFromCwd
|
|
167
|
+
});
|
|
80
168
|
function findNearestNodeModules(startDir) {
|
|
81
169
|
let dir = startDir;
|
|
82
170
|
for (;;) {
|
|
@@ -103,6 +191,8 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
103
191
|
isTSX: true
|
|
104
192
|
}], jsxSyntaxPlugin, stylexBabelPlugin.withOptions({
|
|
105
193
|
...stylexOptions,
|
|
194
|
+
importSources,
|
|
195
|
+
treeshakeCompensation,
|
|
106
196
|
dev,
|
|
107
197
|
unstable_moduleResolution
|
|
108
198
|
})],
|
|
@@ -271,6 +361,23 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
271
361
|
} else {}
|
|
272
362
|
},
|
|
273
363
|
vite: devMode === 'off' ? undefined : {
|
|
364
|
+
config(config) {
|
|
365
|
+
if (!stylexPackages || stylexPackages.length === 0) return;
|
|
366
|
+
const addExcludes = (existing = []) => Array.from(new Set([...existing, ...stylexPackages]));
|
|
367
|
+
return {
|
|
368
|
+
optimizeDeps: {
|
|
369
|
+
...(config?.optimizeDeps || {}),
|
|
370
|
+
exclude: addExcludes(config?.optimizeDeps?.exclude || [])
|
|
371
|
+
},
|
|
372
|
+
ssr: {
|
|
373
|
+
...(config?.ssr || {}),
|
|
374
|
+
optimizeDeps: {
|
|
375
|
+
...(config?.ssr?.optimizeDeps || {}),
|
|
376
|
+
exclude: addExcludes(config?.ssr?.optimizeDeps?.exclude || [])
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
},
|
|
274
381
|
configResolved(config) {
|
|
275
382
|
try {
|
|
276
383
|
viteOutDir = config.build?.outDir || viteOutDir;
|
|
@@ -310,15 +417,15 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
310
417
|
server.httpServer?.once('close', () => clearInterval(interval));
|
|
311
418
|
},
|
|
312
419
|
resolveId(id) {
|
|
313
|
-
if (devMode === 'full' && id
|
|
314
|
-
if (devMode === 'css-only' && id
|
|
420
|
+
if (devMode === 'full' && id.includes('virtual:stylex:runtime')) return id;
|
|
421
|
+
if (devMode === 'css-only' && id.includes('virtual:stylex:css-only')) return id;
|
|
315
422
|
return null;
|
|
316
423
|
},
|
|
317
424
|
load(id) {
|
|
318
|
-
if (devMode === 'full' && id
|
|
425
|
+
if (devMode === 'full' && id.includes('virtual:stylex:runtime')) {
|
|
319
426
|
return VIRTUAL_STYLEX_RUNTIME_SCRIPT;
|
|
320
427
|
}
|
|
321
|
-
if (devMode === 'css-only' && id
|
|
428
|
+
if (devMode === 'css-only' && id.includes('virtual:stylex:css-only')) {
|
|
322
429
|
return VIRTUAL_STYLEX_CSS_ONLY_SCRIPT;
|
|
323
430
|
}
|
|
324
431
|
return null;
|
|
@@ -326,24 +433,26 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
326
433
|
transformIndexHtml() {
|
|
327
434
|
if (devMode !== 'full') return null;
|
|
328
435
|
if (!viteServer) return null;
|
|
436
|
+
const base = viteServer.config.base ?? '';
|
|
329
437
|
return [{
|
|
330
438
|
tag: 'script',
|
|
331
439
|
attrs: {
|
|
332
440
|
type: 'module',
|
|
333
|
-
src: '/@id/virtual:stylex:runtime'
|
|
441
|
+
src: path.join(base, '/@id/virtual:stylex:runtime')
|
|
334
442
|
},
|
|
335
443
|
injectTo: 'head'
|
|
336
444
|
}, {
|
|
337
445
|
tag: 'link',
|
|
338
446
|
attrs: {
|
|
339
447
|
rel: 'stylesheet',
|
|
340
|
-
href: DEV_CSS_PATH
|
|
448
|
+
href: path.join(base, DEV_CSS_PATH)
|
|
341
449
|
},
|
|
342
450
|
injectTo: 'head'
|
|
343
451
|
}];
|
|
344
452
|
},
|
|
345
453
|
handleHotUpdate(ctx) {
|
|
346
|
-
const
|
|
454
|
+
const base = ctx.server.config.base ?? '';
|
|
455
|
+
const cssMod = ctx.server.moduleGraph.getModuleById(path.join(base, 'virtual:stylex:css-module'));
|
|
347
456
|
if (cssMod) {
|
|
348
457
|
ctx.server.moduleGraph.invalidateModule(cssMod);
|
|
349
458
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { type UnpluginInstance } from 'unplugin';
|
|
2
|
+
import type { Options as StyleXOptions } from '@stylexjs/babel-plugin';
|
|
3
|
+
import type { TransformOptions as LightningcssOptions } from 'lightningcss';
|
|
2
4
|
|
|
3
5
|
export default unplugin;
|
|
4
|
-
|
|
6
|
+
|
|
7
|
+
type UserOptions = StyleXOptions & {
|
|
8
|
+
useCSSLayers?: boolean;
|
|
9
|
+
enableLTRRTLComments?: boolean;
|
|
10
|
+
legacyDisableLayers?: boolean;
|
|
11
|
+
lightningcssOptions?: LightningcssOptions;
|
|
12
|
+
cssInjectionTarget?: (filepath: string) => boolean;
|
|
13
|
+
devPersistToDisk?: boolean;
|
|
14
|
+
devMode?: 'full' | 'css-only' | 'off';
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
declare const unplugin: UnpluginInstance<Partial<UserOptions>, false>;
|
package/lib/index.js
CHANGED
|
@@ -13,6 +13,7 @@ var _pluginSyntaxTypescript = _interopRequireDefault(require("@babel/plugin-synt
|
|
|
13
13
|
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
14
14
|
var _nodeFs = _interopRequireDefault(require("node:fs"));
|
|
15
15
|
var _promises = _interopRequireDefault(require("node:fs/promises"));
|
|
16
|
+
var _nodeModule = require("node:module");
|
|
16
17
|
var _lightningcss = require("lightningcss");
|
|
17
18
|
var _browserslist = _interopRequireDefault(require("browserslist"));
|
|
18
19
|
var _devInjectMiddleware = require("./dev-inject-middleware");
|
|
@@ -44,7 +45,84 @@ function processCollectedRulesToCSS(rules, options) {
|
|
|
44
45
|
});
|
|
45
46
|
return code.toString();
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
+
function readJSON(file) {
|
|
49
|
+
try {
|
|
50
|
+
const content = _nodeFs.default.readFileSync(file, 'utf8');
|
|
51
|
+
return JSON.parse(content);
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function findNearestPackageJson(startDir) {
|
|
57
|
+
let dir = startDir;
|
|
58
|
+
for (;;) {
|
|
59
|
+
const candidate = _nodePath.default.join(dir, 'package.json');
|
|
60
|
+
if (_nodeFs.default.existsSync(candidate)) return candidate;
|
|
61
|
+
const parent = _nodePath.default.dirname(dir);
|
|
62
|
+
if (parent === dir) break;
|
|
63
|
+
dir = parent;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
function toPackageName(importSource) {
|
|
68
|
+
const source = typeof importSource === 'string' ? importSource : importSource?.from;
|
|
69
|
+
if (!source || source.startsWith('.') || source.startsWith('/')) return null;
|
|
70
|
+
if (source.startsWith('@')) {
|
|
71
|
+
const [scope, name] = source.split('/');
|
|
72
|
+
if (scope && name) return `${scope}/${name}`;
|
|
73
|
+
}
|
|
74
|
+
const [pkg] = source.split('/');
|
|
75
|
+
return pkg || null;
|
|
76
|
+
}
|
|
77
|
+
function hasStylexDependency(manifest, targetPackages) {
|
|
78
|
+
if (!manifest || typeof manifest !== 'object') return false;
|
|
79
|
+
const depFields = ['dependencies', 'peerDependencies', 'optionalDependencies'];
|
|
80
|
+
for (const field of depFields) {
|
|
81
|
+
const deps = manifest[field];
|
|
82
|
+
if (!deps || typeof deps !== 'object') continue;
|
|
83
|
+
for (const name of Object.keys(deps)) {
|
|
84
|
+
if (targetPackages.has(name)) return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
function discoverStylexPackages({
|
|
90
|
+
importSources,
|
|
91
|
+
explicitPackages,
|
|
92
|
+
rootDir,
|
|
93
|
+
resolver
|
|
94
|
+
}) {
|
|
95
|
+
const targetPackages = new Set(importSources.map(toPackageName).filter(Boolean).concat(['@stylexjs/stylex']));
|
|
96
|
+
const found = new Set(explicitPackages || []);
|
|
97
|
+
const pkgJsonPath = findNearestPackageJson(rootDir);
|
|
98
|
+
if (!pkgJsonPath) return Array.from(found);
|
|
99
|
+
const pkgDir = _nodePath.default.dirname(pkgJsonPath);
|
|
100
|
+
const pkgJson = readJSON(pkgJsonPath);
|
|
101
|
+
if (!pkgJson) return Array.from(found);
|
|
102
|
+
const depFields = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'];
|
|
103
|
+
const deps = new Set();
|
|
104
|
+
for (const field of depFields) {
|
|
105
|
+
const entries = pkgJson[field];
|
|
106
|
+
if (!entries || typeof entries !== 'object') continue;
|
|
107
|
+
for (const name of Object.keys(entries)) deps.add(name);
|
|
108
|
+
}
|
|
109
|
+
for (const dep of deps) {
|
|
110
|
+
let manifestPath = null;
|
|
111
|
+
try {
|
|
112
|
+
manifestPath = resolver.resolve(`${dep}/package.json`, {
|
|
113
|
+
paths: [pkgDir]
|
|
114
|
+
});
|
|
115
|
+
} catch {}
|
|
116
|
+
if (!manifestPath) continue;
|
|
117
|
+
const manifest = readJSON(manifestPath);
|
|
118
|
+
if (hasStylexDependency(manifest, targetPackages)) {
|
|
119
|
+
found.add(dep);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return Array.from(found);
|
|
123
|
+
}
|
|
124
|
+
const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}, metaOptions) => {
|
|
125
|
+
const framework = metaOptions?.framework;
|
|
48
126
|
const {
|
|
49
127
|
dev = process.env.NODE_ENV === 'development' || process.env.BABEL_ENV === 'development',
|
|
50
128
|
unstable_moduleResolution = {
|
|
@@ -59,8 +137,10 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
59
137
|
useCSSLayers = false,
|
|
60
138
|
lightningcssOptions,
|
|
61
139
|
cssInjectionTarget,
|
|
140
|
+
externalPackages = [],
|
|
62
141
|
devPersistToDisk = false,
|
|
63
142
|
devMode = 'full',
|
|
143
|
+
treeshakeCompensation = ['vite', 'rollup', 'rolldown'].includes(framework),
|
|
64
144
|
...stylexOptions
|
|
65
145
|
} = userOptions;
|
|
66
146
|
const stylexRulesById = new Map();
|
|
@@ -83,6 +163,14 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
83
163
|
}
|
|
84
164
|
let viteServer = null;
|
|
85
165
|
let viteOutDir = null;
|
|
166
|
+
const nearestPkgJson = findNearestPackageJson(process.cwd());
|
|
167
|
+
const requireFromCwd = nearestPkgJson ? (0, _nodeModule.createRequire)(nearestPkgJson) : (0, _nodeModule.createRequire)(_nodePath.default.join(process.cwd(), 'package.json'));
|
|
168
|
+
const stylexPackages = discoverStylexPackages({
|
|
169
|
+
importSources,
|
|
170
|
+
explicitPackages: externalPackages,
|
|
171
|
+
rootDir: nearestPkgJson ? _nodePath.default.dirname(nearestPkgJson) : process.cwd(),
|
|
172
|
+
resolver: requireFromCwd
|
|
173
|
+
});
|
|
86
174
|
function findNearestNodeModules(startDir) {
|
|
87
175
|
let dir = startDir;
|
|
88
176
|
for (;;) {
|
|
@@ -109,6 +197,8 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
109
197
|
isTSX: true
|
|
110
198
|
}], _pluginSyntaxJsx.default, _babelPlugin.default.withOptions({
|
|
111
199
|
...stylexOptions,
|
|
200
|
+
importSources,
|
|
201
|
+
treeshakeCompensation,
|
|
112
202
|
dev,
|
|
113
203
|
unstable_moduleResolution
|
|
114
204
|
})],
|
|
@@ -277,6 +367,23 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
277
367
|
} else {}
|
|
278
368
|
},
|
|
279
369
|
vite: devMode === 'off' ? undefined : {
|
|
370
|
+
config(config) {
|
|
371
|
+
if (!stylexPackages || stylexPackages.length === 0) return;
|
|
372
|
+
const addExcludes = (existing = []) => Array.from(new Set([...existing, ...stylexPackages]));
|
|
373
|
+
return {
|
|
374
|
+
optimizeDeps: {
|
|
375
|
+
...(config?.optimizeDeps || {}),
|
|
376
|
+
exclude: addExcludes(config?.optimizeDeps?.exclude || [])
|
|
377
|
+
},
|
|
378
|
+
ssr: {
|
|
379
|
+
...(config?.ssr || {}),
|
|
380
|
+
optimizeDeps: {
|
|
381
|
+
...(config?.ssr?.optimizeDeps || {}),
|
|
382
|
+
exclude: addExcludes(config?.ssr?.optimizeDeps?.exclude || [])
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
},
|
|
280
387
|
configResolved(config) {
|
|
281
388
|
try {
|
|
282
389
|
viteOutDir = config.build?.outDir || viteOutDir;
|
|
@@ -316,15 +423,15 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
316
423
|
server.httpServer?.once('close', () => clearInterval(interval));
|
|
317
424
|
},
|
|
318
425
|
resolveId(id) {
|
|
319
|
-
if (devMode === 'full' && id
|
|
320
|
-
if (devMode === 'css-only' && id
|
|
426
|
+
if (devMode === 'full' && id.includes('virtual:stylex:runtime')) return id;
|
|
427
|
+
if (devMode === 'css-only' && id.includes('virtual:stylex:css-only')) return id;
|
|
321
428
|
return null;
|
|
322
429
|
},
|
|
323
430
|
load(id) {
|
|
324
|
-
if (devMode === 'full' && id
|
|
431
|
+
if (devMode === 'full' && id.includes('virtual:stylex:runtime')) {
|
|
325
432
|
return _consts.VIRTUAL_STYLEX_RUNTIME_SCRIPT;
|
|
326
433
|
}
|
|
327
|
-
if (devMode === 'css-only' && id
|
|
434
|
+
if (devMode === 'css-only' && id.includes('virtual:stylex:css-only')) {
|
|
328
435
|
return _consts.VIRTUAL_STYLEX_CSS_ONLY_SCRIPT;
|
|
329
436
|
}
|
|
330
437
|
return null;
|
|
@@ -332,24 +439,26 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
332
439
|
transformIndexHtml() {
|
|
333
440
|
if (devMode !== 'full') return null;
|
|
334
441
|
if (!viteServer) return null;
|
|
442
|
+
const base = viteServer.config.base ?? '';
|
|
335
443
|
return [{
|
|
336
444
|
tag: 'script',
|
|
337
445
|
attrs: {
|
|
338
446
|
type: 'module',
|
|
339
|
-
src: '/@id/virtual:stylex:runtime'
|
|
447
|
+
src: _nodePath.default.join(base, '/@id/virtual:stylex:runtime')
|
|
340
448
|
},
|
|
341
449
|
injectTo: 'head'
|
|
342
450
|
}, {
|
|
343
451
|
tag: 'link',
|
|
344
452
|
attrs: {
|
|
345
453
|
rel: 'stylesheet',
|
|
346
|
-
href: _consts.DEV_CSS_PATH
|
|
454
|
+
href: _nodePath.default.join(base, _consts.DEV_CSS_PATH)
|
|
347
455
|
},
|
|
348
456
|
injectTo: 'head'
|
|
349
457
|
}];
|
|
350
458
|
},
|
|
351
459
|
handleHotUpdate(ctx) {
|
|
352
|
-
const
|
|
460
|
+
const base = ctx.server.config.base ?? '';
|
|
461
|
+
const cssMod = ctx.server.moduleGraph.getModuleById(_nodePath.default.join(base, 'virtual:stylex:css-module'));
|
|
353
462
|
if (cssMod) {
|
|
354
463
|
ctx.server.moduleGraph.invalidateModule(cssMod);
|
|
355
464
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stylexjs/unplugin",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
4
4
|
"private": false,
|
|
5
|
-
"publishConfig": {
|
|
6
|
-
"access": "public"
|
|
7
|
-
},
|
|
8
5
|
"description": "Universal bundler plugin for StyleX using unplugin",
|
|
9
6
|
"license": "MIT",
|
|
10
7
|
"main": "./lib/index.js",
|
|
@@ -31,14 +28,14 @@
|
|
|
31
28
|
"test": "jest"
|
|
32
29
|
},
|
|
33
30
|
"peerDependencies": {
|
|
34
|
-
"unplugin": "^
|
|
31
|
+
"unplugin": "^2.3.11"
|
|
35
32
|
},
|
|
36
33
|
"dependencies": {
|
|
37
34
|
"@babel/core": "^7.26.8",
|
|
38
35
|
"@babel/plugin-syntax-flow": "^7.26.0",
|
|
39
36
|
"@babel/plugin-syntax-jsx": "^7.25.9",
|
|
40
37
|
"@babel/plugin-syntax-typescript": "^7.25.9",
|
|
41
|
-
"@stylexjs/babel-plugin": "0.17.
|
|
38
|
+
"@stylexjs/babel-plugin": "0.17.2",
|
|
42
39
|
"browserslist": "^4.24.0",
|
|
43
40
|
"lightningcss": "^1.29.1"
|
|
44
41
|
},
|