@stylexjs/unplugin 0.17.0 → 0.17.1
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 +116 -8
- package/lib/index.d.ts +14 -1
- package/lib/index.js +116 -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,7 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
103
191
|
isTSX: true
|
|
104
192
|
}], jsxSyntaxPlugin, stylexBabelPlugin.withOptions({
|
|
105
193
|
...stylexOptions,
|
|
194
|
+
treeshakeCompensation,
|
|
106
195
|
dev,
|
|
107
196
|
unstable_moduleResolution
|
|
108
197
|
})],
|
|
@@ -271,6 +360,23 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
271
360
|
} else {}
|
|
272
361
|
},
|
|
273
362
|
vite: devMode === 'off' ? undefined : {
|
|
363
|
+
config(config) {
|
|
364
|
+
if (!stylexPackages || stylexPackages.length === 0) return;
|
|
365
|
+
const addExcludes = (existing = []) => Array.from(new Set([...existing, ...stylexPackages]));
|
|
366
|
+
return {
|
|
367
|
+
optimizeDeps: {
|
|
368
|
+
...(config?.optimizeDeps || {}),
|
|
369
|
+
exclude: addExcludes(config?.optimizeDeps?.exclude || [])
|
|
370
|
+
},
|
|
371
|
+
ssr: {
|
|
372
|
+
...(config?.ssr || {}),
|
|
373
|
+
optimizeDeps: {
|
|
374
|
+
...(config?.ssr?.optimizeDeps || {}),
|
|
375
|
+
exclude: addExcludes(config?.ssr?.optimizeDeps?.exclude || [])
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
},
|
|
274
380
|
configResolved(config) {
|
|
275
381
|
try {
|
|
276
382
|
viteOutDir = config.build?.outDir || viteOutDir;
|
|
@@ -310,15 +416,15 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
310
416
|
server.httpServer?.once('close', () => clearInterval(interval));
|
|
311
417
|
},
|
|
312
418
|
resolveId(id) {
|
|
313
|
-
if (devMode === 'full' && id
|
|
314
|
-
if (devMode === 'css-only' && id
|
|
419
|
+
if (devMode === 'full' && id.includes('virtual:stylex:runtime')) return id;
|
|
420
|
+
if (devMode === 'css-only' && id.includes('virtual:stylex:css-only')) return id;
|
|
315
421
|
return null;
|
|
316
422
|
},
|
|
317
423
|
load(id) {
|
|
318
|
-
if (devMode === 'full' && id
|
|
424
|
+
if (devMode === 'full' && id.includes('virtual:stylex:runtime')) {
|
|
319
425
|
return VIRTUAL_STYLEX_RUNTIME_SCRIPT;
|
|
320
426
|
}
|
|
321
|
-
if (devMode === 'css-only' && id
|
|
427
|
+
if (devMode === 'css-only' && id.includes('virtual:stylex:css-only')) {
|
|
322
428
|
return VIRTUAL_STYLEX_CSS_ONLY_SCRIPT;
|
|
323
429
|
}
|
|
324
430
|
return null;
|
|
@@ -326,24 +432,26 @@ const unpluginInstance = createUnplugin((userOptions = {}) => {
|
|
|
326
432
|
transformIndexHtml() {
|
|
327
433
|
if (devMode !== 'full') return null;
|
|
328
434
|
if (!viteServer) return null;
|
|
435
|
+
const base = viteServer.config.base ?? '';
|
|
329
436
|
return [{
|
|
330
437
|
tag: 'script',
|
|
331
438
|
attrs: {
|
|
332
439
|
type: 'module',
|
|
333
|
-
src: '/@id/virtual:stylex:runtime'
|
|
440
|
+
src: path.join(base, '/@id/virtual:stylex:runtime')
|
|
334
441
|
},
|
|
335
442
|
injectTo: 'head'
|
|
336
443
|
}, {
|
|
337
444
|
tag: 'link',
|
|
338
445
|
attrs: {
|
|
339
446
|
rel: 'stylesheet',
|
|
340
|
-
href: DEV_CSS_PATH
|
|
447
|
+
href: path.join(base, DEV_CSS_PATH)
|
|
341
448
|
},
|
|
342
449
|
injectTo: 'head'
|
|
343
450
|
}];
|
|
344
451
|
},
|
|
345
452
|
handleHotUpdate(ctx) {
|
|
346
|
-
const
|
|
453
|
+
const base = ctx.server.config.base ?? '';
|
|
454
|
+
const cssMod = ctx.server.moduleGraph.getModuleById(path.join(base, 'virtual:stylex:css-module'));
|
|
347
455
|
if (cssMod) {
|
|
348
456
|
ctx.server.moduleGraph.invalidateModule(cssMod);
|
|
349
457
|
}
|
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,7 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
109
197
|
isTSX: true
|
|
110
198
|
}], _pluginSyntaxJsx.default, _babelPlugin.default.withOptions({
|
|
111
199
|
...stylexOptions,
|
|
200
|
+
treeshakeCompensation,
|
|
112
201
|
dev,
|
|
113
202
|
unstable_moduleResolution
|
|
114
203
|
})],
|
|
@@ -277,6 +366,23 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
277
366
|
} else {}
|
|
278
367
|
},
|
|
279
368
|
vite: devMode === 'off' ? undefined : {
|
|
369
|
+
config(config) {
|
|
370
|
+
if (!stylexPackages || stylexPackages.length === 0) return;
|
|
371
|
+
const addExcludes = (existing = []) => Array.from(new Set([...existing, ...stylexPackages]));
|
|
372
|
+
return {
|
|
373
|
+
optimizeDeps: {
|
|
374
|
+
...(config?.optimizeDeps || {}),
|
|
375
|
+
exclude: addExcludes(config?.optimizeDeps?.exclude || [])
|
|
376
|
+
},
|
|
377
|
+
ssr: {
|
|
378
|
+
...(config?.ssr || {}),
|
|
379
|
+
optimizeDeps: {
|
|
380
|
+
...(config?.ssr?.optimizeDeps || {}),
|
|
381
|
+
exclude: addExcludes(config?.ssr?.optimizeDeps?.exclude || [])
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
},
|
|
280
386
|
configResolved(config) {
|
|
281
387
|
try {
|
|
282
388
|
viteOutDir = config.build?.outDir || viteOutDir;
|
|
@@ -316,15 +422,15 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
316
422
|
server.httpServer?.once('close', () => clearInterval(interval));
|
|
317
423
|
},
|
|
318
424
|
resolveId(id) {
|
|
319
|
-
if (devMode === 'full' && id
|
|
320
|
-
if (devMode === 'css-only' && id
|
|
425
|
+
if (devMode === 'full' && id.includes('virtual:stylex:runtime')) return id;
|
|
426
|
+
if (devMode === 'css-only' && id.includes('virtual:stylex:css-only')) return id;
|
|
321
427
|
return null;
|
|
322
428
|
},
|
|
323
429
|
load(id) {
|
|
324
|
-
if (devMode === 'full' && id
|
|
430
|
+
if (devMode === 'full' && id.includes('virtual:stylex:runtime')) {
|
|
325
431
|
return _consts.VIRTUAL_STYLEX_RUNTIME_SCRIPT;
|
|
326
432
|
}
|
|
327
|
-
if (devMode === 'css-only' && id
|
|
433
|
+
if (devMode === 'css-only' && id.includes('virtual:stylex:css-only')) {
|
|
328
434
|
return _consts.VIRTUAL_STYLEX_CSS_ONLY_SCRIPT;
|
|
329
435
|
}
|
|
330
436
|
return null;
|
|
@@ -332,24 +438,26 @@ const unpluginInstance = (0, _unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
332
438
|
transformIndexHtml() {
|
|
333
439
|
if (devMode !== 'full') return null;
|
|
334
440
|
if (!viteServer) return null;
|
|
441
|
+
const base = viteServer.config.base ?? '';
|
|
335
442
|
return [{
|
|
336
443
|
tag: 'script',
|
|
337
444
|
attrs: {
|
|
338
445
|
type: 'module',
|
|
339
|
-
src: '/@id/virtual:stylex:runtime'
|
|
446
|
+
src: _nodePath.default.join(base, '/@id/virtual:stylex:runtime')
|
|
340
447
|
},
|
|
341
448
|
injectTo: 'head'
|
|
342
449
|
}, {
|
|
343
450
|
tag: 'link',
|
|
344
451
|
attrs: {
|
|
345
452
|
rel: 'stylesheet',
|
|
346
|
-
href: _consts.DEV_CSS_PATH
|
|
453
|
+
href: _nodePath.default.join(base, _consts.DEV_CSS_PATH)
|
|
347
454
|
},
|
|
348
455
|
injectTo: 'head'
|
|
349
456
|
}];
|
|
350
457
|
},
|
|
351
458
|
handleHotUpdate(ctx) {
|
|
352
|
-
const
|
|
459
|
+
const base = ctx.server.config.base ?? '';
|
|
460
|
+
const cssMod = ctx.server.moduleGraph.getModuleById(_nodePath.default.join(base, 'virtual:stylex:css-module'));
|
|
353
461
|
if (cssMod) {
|
|
354
462
|
ctx.server.moduleGraph.invalidateModule(cssMod);
|
|
355
463
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stylexjs/unplugin",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
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.1",
|
|
42
39
|
"browserslist": "^4.24.0",
|
|
43
40
|
"lightningcss": "^1.29.1"
|
|
44
41
|
},
|