@farm.js/stylex 0.1.0-beta.0
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/LICENSE +22 -0
- package/README.md +65 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +27 -0
- package/dist/html.d.ts +5 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +57 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Farm.js Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# `@farm.js/stylex`
|
|
2
|
+
|
|
3
|
+
Compile [StyleX](https://stylexjs.com/) in Farm with extracted production CSS, pre-paint
|
|
4
|
+
development styles, and CSS HMR.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pnpm add @farm.js/stylex @stylexjs/stylex
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Configure
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { defineConfig } from "@farm.js/core";
|
|
16
|
+
import { stylex } from "@farm.js/stylex";
|
|
17
|
+
|
|
18
|
+
export default defineConfig({
|
|
19
|
+
plugins: [stylex()],
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Use the normal StyleX authoring API in application components:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import * as stylex from "@stylexjs/stylex";
|
|
27
|
+
|
|
28
|
+
const styles = stylex.create({
|
|
29
|
+
button: {
|
|
30
|
+
backgroundColor: "#111",
|
|
31
|
+
borderRadius: 8,
|
|
32
|
+
color: "white",
|
|
33
|
+
padding: "10px 16px",
|
|
34
|
+
":hover": { backgroundColor: "#333" },
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export function Button() {
|
|
39
|
+
return <button {...stylex.props(styles.button)}>Create project</button>;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Farm selects StyleX's development or production compiler mode, injects the development stylesheet
|
|
44
|
+
before paint, connects HMR, and appends extracted production rules to Farm's CSS output. Do not add
|
|
45
|
+
StyleX virtual modules or stylesheet tags yourself.
|
|
46
|
+
|
|
47
|
+
## External packages
|
|
48
|
+
|
|
49
|
+
Dependencies are normally optimized as already-built code. Add a package to `externalPackages`
|
|
50
|
+
when it publishes source containing uncompiled `stylex.create()` calls:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
stylex({
|
|
54
|
+
externalPackages: ["@acme/ui", "shared-stylex-components"],
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Farm then excludes those packages from Vite dependency optimization and runs the StyleX compiler
|
|
59
|
+
over them. Pass package names only, not file paths, glob patterns, or package subpaths. You do not
|
|
60
|
+
need this option for packages that publish compiled StyleX output or ordinary CSS.
|
|
61
|
+
|
|
62
|
+
Other StyleX compiler options such as `useCSSLayers`, `importSources`, `babelConfig`,
|
|
63
|
+
`unstable_moduleResolution`, `lightningcssOptions`, and `cssInjectionTarget` pass through to
|
|
64
|
+
`@stylexjs/unplugin`. Farm owns `dev`, `devMode`, and `devPersistToDisk` so development and build
|
|
65
|
+
behavior cannot drift apart.
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { UserOptions } from "@stylexjs/unplugin";
|
|
2
|
+
type FarmManagedStyleXOption = "dev" | "devMode" | "devPersistToDisk";
|
|
3
|
+
/** StyleX compiler options. Farm owns the development mode and browser hookup. */
|
|
4
|
+
export type StyleXOptions = Omit<Partial<UserOptions>, FarmManagedStyleXOption | "externalPackages"> & {
|
|
5
|
+
/**
|
|
6
|
+
* Packages in `node_modules` that publish uncompiled StyleX source.
|
|
7
|
+
* Farm de-optimizes and compiles these packages as application source.
|
|
8
|
+
*/
|
|
9
|
+
externalPackages?: readonly string[];
|
|
10
|
+
};
|
|
11
|
+
export interface ResolvedStyleXOptions extends Omit<StyleXOptions, "externalPackages"> {
|
|
12
|
+
externalPackages: string[];
|
|
13
|
+
}
|
|
14
|
+
export declare function resolveStylexOptions(options?: StyleXOptions): ResolvedStyleXOptions;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,KAAK,uBAAuB,GAAG,KAAK,GAAG,SAAS,GAAG,kBAAkB,CAAC;AAEtE,kFAAkF;AAClF,MAAM,MAAM,aAAa,GAAG,IAAI,CAC9B,OAAO,CAAC,WAAW,CAAC,EACpB,uBAAuB,GAAG,kBAAkB,CAC7C,GAAG;IACF;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,CAAC;AAEF,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,aAAa,EAAE,kBAAkB,CAAC;IACpF,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,aAAkB,GAAG,qBAAqB,CAqBvF"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function resolveStylexOptions(options = {}) {
|
|
2
|
+
const externalPackages = options.externalPackages ?? [];
|
|
3
|
+
if (!Array.isArray(externalPackages)) {
|
|
4
|
+
throw new TypeError("[farm:stylex] externalPackages must be an array of package names");
|
|
5
|
+
}
|
|
6
|
+
const normalizedPackages = [];
|
|
7
|
+
for (const value of externalPackages) {
|
|
8
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
9
|
+
throw new TypeError("[farm:stylex] externalPackages must contain non-empty package names");
|
|
10
|
+
}
|
|
11
|
+
const packageName = value.trim();
|
|
12
|
+
if (!isPackageName(packageName)) {
|
|
13
|
+
throw new TypeError(`[farm:stylex] externalPackages must contain package names, not paths or subpath imports: ${JSON.stringify(value)}`);
|
|
14
|
+
}
|
|
15
|
+
if (!normalizedPackages.includes(packageName))
|
|
16
|
+
normalizedPackages.push(packageName);
|
|
17
|
+
}
|
|
18
|
+
return { ...options, externalPackages: normalizedPackages };
|
|
19
|
+
}
|
|
20
|
+
function isPackageName(value) {
|
|
21
|
+
if (value.startsWith(".") || value.startsWith("/") || value.includes("\\"))
|
|
22
|
+
return false;
|
|
23
|
+
const segments = value.split("/");
|
|
24
|
+
return value.startsWith("@")
|
|
25
|
+
? segments.length === 2 && segments.every(Boolean)
|
|
26
|
+
: segments.length === 1;
|
|
27
|
+
}
|
package/dist/html.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Add StyleX's development CSS before paint and connect its HMR runtime. */
|
|
2
|
+
export declare function injectStylexDevelopmentAssets(html: string, basePath?: string): string;
|
|
3
|
+
/** Strip Farm's mount path before StyleX's development middleware resolves its virtual assets. */
|
|
4
|
+
export declare function stripStylexDevelopmentBasePath(url: string, basePath: string): string;
|
|
5
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AAGA,6EAA6E;AAC7E,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAiBlF;AAED,kGAAkG;AAClG,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWpF"}
|
package/dist/html.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const STYLEX_DEVELOPMENT_CSS = "/virtual:stylex.css";
|
|
2
|
+
const STYLEX_DEVELOPMENT_RUNTIME = "/@id/virtual:stylex:runtime";
|
|
3
|
+
/** Add StyleX's development CSS before paint and connect its HMR runtime. */
|
|
4
|
+
export function injectStylexDevelopmentAssets(html, basePath = "/") {
|
|
5
|
+
const closingHead = html.search(/<\/head\s*>/i);
|
|
6
|
+
if (closingHead < 0)
|
|
7
|
+
return html;
|
|
8
|
+
const head = html.slice(0, closingHead);
|
|
9
|
+
const cssUrl = withBasePath(STYLEX_DEVELOPMENT_CSS, basePath);
|
|
10
|
+
const runtimeUrl = withBasePath(STYLEX_DEVELOPMENT_RUNTIME, basePath);
|
|
11
|
+
const tags = [];
|
|
12
|
+
if (!hasStylexAsset(head, "link", "css")) {
|
|
13
|
+
tags.push(`<link rel="stylesheet" href="${cssUrl}" data-farm-stylex="css">`);
|
|
14
|
+
}
|
|
15
|
+
if (!hasStylexAsset(head, "script", "runtime")) {
|
|
16
|
+
tags.push(`<script type="module" src="${runtimeUrl}" data-farm-stylex="runtime"></script>`);
|
|
17
|
+
}
|
|
18
|
+
if (tags.length === 0)
|
|
19
|
+
return html;
|
|
20
|
+
return `${html.slice(0, closingHead)}${tags.join("")}${html.slice(closingHead)}`;
|
|
21
|
+
}
|
|
22
|
+
/** Strip Farm's mount path before StyleX's development middleware resolves its virtual assets. */
|
|
23
|
+
export function stripStylexDevelopmentBasePath(url, basePath) {
|
|
24
|
+
const prefix = normalizeBasePath(basePath);
|
|
25
|
+
if (!prefix)
|
|
26
|
+
return url;
|
|
27
|
+
for (const asset of [STYLEX_DEVELOPMENT_CSS, STYLEX_DEVELOPMENT_RUNTIME]) {
|
|
28
|
+
const prefixedAsset = `${prefix}${asset}`;
|
|
29
|
+
if (url === prefixedAsset || url.startsWith(`${prefixedAsset}?`)) {
|
|
30
|
+
return url.slice(prefix.length);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return url;
|
|
34
|
+
}
|
|
35
|
+
function hasStylexAsset(html, tagName, value) {
|
|
36
|
+
const tags = tagName === "link"
|
|
37
|
+
? html.matchAll(/<link\b(?:[^>"']|"[^"]*"|'[^']*')*>/gi)
|
|
38
|
+
: html.matchAll(/<script\b(?:[^>"']|"[^"]*"|'[^']*')*>/gi);
|
|
39
|
+
for (const tag of tags) {
|
|
40
|
+
const attributes = tag[0].slice(tagName.length + 1, -1);
|
|
41
|
+
const parsed = attributes.matchAll(/([^\s"'<>=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>]+)))?/g);
|
|
42
|
+
for (const attribute of parsed) {
|
|
43
|
+
const attributeValue = attribute[2] ?? attribute[3] ?? attribute[4];
|
|
44
|
+
if (attribute[1]?.toLowerCase() === "data-farm-stylex" && attributeValue === value) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
function withBasePath(url, basePath) {
|
|
52
|
+
return `${normalizeBasePath(basePath)}${url}`;
|
|
53
|
+
}
|
|
54
|
+
function normalizeBasePath(basePath) {
|
|
55
|
+
const normalized = basePath.replace(/^\/+|\/+$/g, "");
|
|
56
|
+
return normalized ? `/${normalized}` : "";
|
|
57
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type StyleXOptions } from "./config.js";
|
|
2
|
+
export type { StyleXOptions };
|
|
3
|
+
/** Compile StyleX and connect its extracted CSS to Farm development and production builds. */
|
|
4
|
+
export declare function stylex(options?: StyleXOptions): import("@farm.js/core/plugin").FarmPlugin;
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAGvE,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,8FAA8F;AAC9F,wBAAgB,MAAM,CAAC,OAAO,GAAE,aAAkB,6CAuDjD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { definePlugin } from "@farm.js/core/plugin";
|
|
2
|
+
import stylexUnplugin from "@stylexjs/unplugin";
|
|
3
|
+
import { resolveStylexOptions } from "./config.js";
|
|
4
|
+
import { injectStylexDevelopmentAssets, stripStylexDevelopmentBasePath } from "./html.js";
|
|
5
|
+
/** Compile StyleX and connect its extracted CSS to Farm development and production builds. */
|
|
6
|
+
export function stylex(options = {}) {
|
|
7
|
+
const resolved = resolveStylexOptions(options);
|
|
8
|
+
let development = false;
|
|
9
|
+
let configuredBasePath = "/";
|
|
10
|
+
return definePlugin({
|
|
11
|
+
name: "farm:stylex",
|
|
12
|
+
enforce: "pre",
|
|
13
|
+
configure(config, context) {
|
|
14
|
+
if ((config.plugins ?? []).filter((candidate) => candidate.name === "farm:stylex").length > 1) {
|
|
15
|
+
throw new Error("[farm:stylex] Configure StyleX in one stylex() plugin instance");
|
|
16
|
+
}
|
|
17
|
+
development = context.isDev;
|
|
18
|
+
configuredBasePath = readBasePath(config.basePath) ?? "/";
|
|
19
|
+
// @stylexjs/unplugin documents and implements externalPackages, but its
|
|
20
|
+
// 0.19.0 UserOptions declaration does not include the property yet.
|
|
21
|
+
const compilerOptions = {
|
|
22
|
+
...resolved,
|
|
23
|
+
externalPackages: [...resolved.externalPackages],
|
|
24
|
+
dev: context.isDev,
|
|
25
|
+
devMode: context.isDev ? "full" : "off",
|
|
26
|
+
};
|
|
27
|
+
const vitePlugin = createStylexVitePlugin(compilerOptions, context.isDev);
|
|
28
|
+
const basePathPlugin = context.isDev && hasBasePath(configuredBasePath)
|
|
29
|
+
? createStylexBasePathVitePlugin(configuredBasePath)
|
|
30
|
+
: undefined;
|
|
31
|
+
return {
|
|
32
|
+
...config,
|
|
33
|
+
vite: {
|
|
34
|
+
...config.vite,
|
|
35
|
+
plugins: [
|
|
36
|
+
...(basePathPlugin ? [basePathPlugin] : []),
|
|
37
|
+
vitePlugin,
|
|
38
|
+
...(config.vite?.plugins ?? []),
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
render: {
|
|
44
|
+
html(html, _render, context) {
|
|
45
|
+
if (!development)
|
|
46
|
+
return html;
|
|
47
|
+
return injectStylexDevelopmentAssets(html, readBasePath(context.config.basePath) ?? configuredBasePath);
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function readBasePath(value) {
|
|
53
|
+
return typeof value === "string" ? value : undefined;
|
|
54
|
+
}
|
|
55
|
+
function hasBasePath(value) {
|
|
56
|
+
return value.replace(/^\/+|\/+$/g, "").length > 0;
|
|
57
|
+
}
|
|
58
|
+
function createStylexBasePathVitePlugin(basePath) {
|
|
59
|
+
return {
|
|
60
|
+
name: "farm:stylex-base-path",
|
|
61
|
+
enforce: "pre",
|
|
62
|
+
configureServer(server) {
|
|
63
|
+
server.middlewares.use((request, _response, next) => {
|
|
64
|
+
if (request.url) {
|
|
65
|
+
request.url = stripStylexDevelopmentBasePath(request.url, basePath);
|
|
66
|
+
}
|
|
67
|
+
next();
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function createStylexVitePlugin(options, development) {
|
|
73
|
+
const plugins = stylexUnplugin.vite(options);
|
|
74
|
+
if (development)
|
|
75
|
+
return plugins;
|
|
76
|
+
const keepProductionTransforms = (plugin) => ({
|
|
77
|
+
...plugin,
|
|
78
|
+
// Farm evaluates routes through an internal Vite server during builds.
|
|
79
|
+
// Keep compiler transforms active there without starting StyleX's dev
|
|
80
|
+
// middleware, HMR interval, or HTML injection hooks.
|
|
81
|
+
apply: () => true,
|
|
82
|
+
configureServer: undefined,
|
|
83
|
+
handleHotUpdate: undefined,
|
|
84
|
+
transformIndexHtml: undefined,
|
|
85
|
+
});
|
|
86
|
+
return Array.isArray(plugins)
|
|
87
|
+
? plugins.map((plugin) => keepProductionTransforms(plugin))
|
|
88
|
+
: keepProductionTransforms(plugins);
|
|
89
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@farm.js/stylex",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"description": "Zero-config StyleX compilation and HMR for Farm.js applications",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"css-in-js",
|
|
7
|
+
"farm.js",
|
|
8
|
+
"stylex",
|
|
9
|
+
"vite"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/farming-labs/farm.js",
|
|
15
|
+
"directory": "packages/farm-stylex"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "./dist/index.js",
|
|
22
|
+
"module": "./dist/index.js",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"import": "./dist/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@stylexjs/unplugin": "^0.19.0",
|
|
35
|
+
"unplugin": "^2.3.11",
|
|
36
|
+
"@farm.js/core": "0.1.0-beta.92"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@stylexjs/stylex": "^0.19.0",
|
|
40
|
+
"@types/node": "^20.10.5",
|
|
41
|
+
"typescript": "^5.3.3",
|
|
42
|
+
"vite": "^5.0.10",
|
|
43
|
+
"vitest": "^3.2.7"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@stylexjs/stylex": "^0.19.0"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=22.13.0"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc",
|
|
53
|
+
"dev": "tsc --watch",
|
|
54
|
+
"type-check": "tsc --noEmit",
|
|
55
|
+
"test": "vitest run"
|
|
56
|
+
}
|
|
57
|
+
}
|