Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .changeset/runtime-helper-packages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@tsrx/runtime": patch
"@tsrx/react-runtime": patch
"@tsrx/preact-runtime": patch
"@tsrx/solid-runtime": patch
"@tsrx/vue-runtime": patch
"@tsrx/core": patch
"@tsrx/react": patch
"@tsrx/preact": patch
"@tsrx/solid": patch
"@tsrx/vue": patch
"@tsrx/vite-plugin-react": patch
"@tsrx/vite-plugin-preact": patch
"@tsrx/vite-plugin-solid": patch
"@tsrx/vite-plugin-vue": patch
"@tsrx/rspack-plugin-react": patch
"@tsrx/rspack-plugin-preact": patch
"@tsrx/rspack-plugin-solid": patch
"@tsrx/rspack-plugin-vue": patch
"@tsrx/bun-plugin-react": patch
"@tsrx/bun-plugin-preact": patch
"@tsrx/bun-plugin-solid": patch
"@tsrx/bun-plugin-vue": patch
"@tsrx/turbopack-plugin-react": patch
---

Split compiler-emitted helpers into shared and renderer-specific runtime packages,
and add opt-in direct runtime imports across supported build integrations.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"copy-tree-sitter-queries": "node ./scripts/copy-tree-sitter-queries.js",
"sync-zed-grammar-rev": "node scripts/sync-zed-grammar-rev.js",
"bench": "node benchmarks/tracked-values.js",
"typecheck": "tsgo --noEmit -p packages/ripple/tsconfig.typecheck.json && tsgo --noEmit -p packages/tsrx/tsconfig.json && tsgo --noEmit -p packages/tsrx-ripple/tsconfig.json && tsgo --noEmit -p packages/tsrx-react/tsconfig.json && tsgo --noEmit -p packages/tsrx-preact/tsconfig.json && tsgo --noEmit -p packages/tsrx-solid/tsconfig.json && tsgo --noEmit -p packages/tsrx-vue/tsconfig.json && tsgo --noEmit -p packages/vite-plugin-react/tsconfig.json && tsgo --noEmit -p packages/rspack-plugin-react/tsconfig.json && tsgo --noEmit -p packages/rspack-plugin-preact/tsconfig.json && tsgo --noEmit -p packages/rspack-plugin-solid/tsconfig.json && tsgo --noEmit -p packages/rspack-plugin-vue/tsconfig.json && tsgo --noEmit -p packages/turbopack-plugin-react/tsconfig.json && tsgo --noEmit -p packages/vite-plugin-solid/tsconfig.json && tsgo --noEmit -p packages/vite-plugin-vue/tsconfig.json && tsgo --noEmit -p packages/cli/tsconfig.json && tsgo --noEmit -p packages/create-ripple/tsconfig.json && tsgo --noEmit -p packages/eslint-parser/tsconfig.json && tsgo --noEmit -p packages/eslint-plugin/tsconfig.json && tsgo --noEmit -p packages/tsrx-mcp/tsconfig.typecheck.json && tsgo --noEmit -p packages/language-server/tsconfig.typecheck.json && tsgo --noEmit -p packages/prettier-plugin/tsconfig.typecheck.json && tsgo --noEmit -p packages/adapter/tsconfig.typecheck.json && tsgo --noEmit -p packages/adapter-bun/tsconfig.typecheck.json && tsgo --noEmit -p packages/bun-plugin-preact/tsconfig.typecheck.json && tsgo --noEmit -p packages/bun-plugin-react/tsconfig.typecheck.json && tsgo --noEmit -p packages/bun-plugin-vue/tsconfig.typecheck.json && tsgo --noEmit -p packages/bun-plugin-solid/tsconfig.typecheck.json && tsgo --noEmit -p packages/adapter-node/tsconfig.typecheck.json && tsgo --noEmit -p packages/adapter-vercel/tsconfig.typecheck.json && tsgo --noEmit -p packages/rollup-plugin/tsconfig.typecheck.json && tsgo --noEmit -p packages/typescript-plugin/tsconfig.typecheck.json && tsgo --noEmit -p packages/vite-plugin/tsconfig.typecheck.json && tsgo --noEmit -p packages/vscode-plugin/tsconfig.typecheck.json"
"typecheck": "tsgo --noEmit -p packages/ripple/tsconfig.typecheck.json && tsgo --noEmit -p packages/tsrx/tsconfig.json && tsgo --noEmit -p packages/tsrx-runtime/tsconfig.json && tsgo --noEmit -p packages/tsrx-react-runtime/tsconfig.json && tsgo --noEmit -p packages/tsrx-preact-runtime/tsconfig.json && tsgo --noEmit -p packages/tsrx-solid-runtime/tsconfig.json && tsgo --noEmit -p packages/tsrx-vue-runtime/tsconfig.json && tsgo --noEmit -p packages/tsrx-ripple/tsconfig.json && tsgo --noEmit -p packages/tsrx-react/tsconfig.json && tsgo --noEmit -p packages/tsrx-preact/tsconfig.json && tsgo --noEmit -p packages/tsrx-solid/tsconfig.json && tsgo --noEmit -p packages/tsrx-vue/tsconfig.json && tsgo --noEmit -p packages/vite-plugin-react/tsconfig.json && tsgo --noEmit -p packages/rspack-plugin-react/tsconfig.json && tsgo --noEmit -p packages/rspack-plugin-preact/tsconfig.json && tsgo --noEmit -p packages/rspack-plugin-solid/tsconfig.json && tsgo --noEmit -p packages/rspack-plugin-vue/tsconfig.json && tsgo --noEmit -p packages/turbopack-plugin-react/tsconfig.json && tsgo --noEmit -p packages/vite-plugin-solid/tsconfig.json && tsgo --noEmit -p packages/vite-plugin-vue/tsconfig.json && tsgo --noEmit -p packages/cli/tsconfig.json && tsgo --noEmit -p packages/create-ripple/tsconfig.json && tsgo --noEmit -p packages/eslint-parser/tsconfig.json && tsgo --noEmit -p packages/eslint-plugin/tsconfig.json && tsgo --noEmit -p packages/tsrx-mcp/tsconfig.typecheck.json && tsgo --noEmit -p packages/language-server/tsconfig.typecheck.json && tsgo --noEmit -p packages/prettier-plugin/tsconfig.typecheck.json && tsgo --noEmit -p packages/adapter/tsconfig.typecheck.json && tsgo --noEmit -p packages/adapter-bun/tsconfig.typecheck.json && tsgo --noEmit -p packages/bun-plugin-preact/tsconfig.typecheck.json && tsgo --noEmit -p packages/bun-plugin-react/tsconfig.typecheck.json && tsgo --noEmit -p packages/bun-plugin-vue/tsconfig.typecheck.json && tsgo --noEmit -p packages/bun-plugin-solid/tsconfig.typecheck.json && tsgo --noEmit -p packages/adapter-node/tsconfig.typecheck.json && tsgo --noEmit -p packages/adapter-vercel/tsconfig.typecheck.json && tsgo --noEmit -p packages/rollup-plugin/tsconfig.typecheck.json && tsgo --noEmit -p packages/typescript-plugin/tsconfig.typecheck.json && tsgo --noEmit -p packages/vite-plugin/tsconfig.typecheck.json && tsgo --noEmit -p packages/vscode-plugin/tsconfig.typecheck.json"
},
"devDependencies": {
"@changesets/changelog-github": "catalog:default",
Expand Down
2 changes: 2 additions & 0 deletions packages/bun-plugin-preact/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const CSS_QUERY_PATTERN = /\?tsrx-css&lang\.css$/;
* exclude?: RegExp | RegExp[],
* jsxImportSource?: string,
* suspenseSource?: string,
* runtimeImports?: 'compiler' | 'direct',
* emitCss?: boolean,
* }} TsrxPreactBunPluginOptions
*/
Expand Down Expand Up @@ -93,6 +94,7 @@ export function tsrxPreact(options = {}) {
const emit_css = options.emitCss ?? true;
const compile_options = {
suspenseSource: options.suspenseSource,
runtimeImports: options.runtimeImports,
};

/** @type {Map<string, string>} */
Expand Down
19 changes: 19 additions & 0 deletions packages/bun-plugin-preact/tests/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,25 @@ describe('@tsrx/bun-plugin-preact', () => {
}
});

it('forwards direct runtime imports to the compiler', async () => {
const dir = await mkdtemp(path.join(os.tmpdir(), 'tsrx-bun-plugin-preact-runtime-'));
try {
const file_path = path.join(dir, 'App.tsrx');
await writeFile(
file_path,
`export function App(props) @{
<input {...props} />
}`,
);

const hooks = setup_plugin({ runtimeImports: 'direct' });
const transformed = await load_tsrx(hooks, file_path);
expect(transformed?.contents).toContain("from '@tsrx/preact-runtime/ref'");
} finally {
await rm(dir, { recursive: true, force: true });
}
});

it('honors exclude filters', async () => {
const hooks = setup_plugin({ exclude: /ignored\.tsrx$/ }, { target: 'browser' });
const transformed = await load_tsrx(hooks, '/project/ignored.tsrx');
Expand Down
1 change: 1 addition & 0 deletions packages/bun-plugin-preact/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface TsrxPreactBunPluginOptions {
exclude?: RegExp | RegExp[];
jsxImportSource?: string;
suspenseSource?: string;
runtimeImports?: 'compiler' | 'direct';
emitCss?: boolean;
}

Expand Down
4 changes: 3 additions & 1 deletion packages/bun-plugin-react/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const CSS_QUERY_PATTERN = /\?tsrx-css&lang\.css$/;
* exclude?: RegExp | RegExp[],
* jsxImportSource?: string,
* emitCss?: boolean,
* runtimeImports?: 'compiler' | 'direct',
* }} TsrxReactBunPluginOptions
*/

Expand Down Expand Up @@ -90,6 +91,7 @@ function create_transpiler(jsx_import_source, target) {
export function tsrxReact(options = {}) {
const jsx_import_source = options.jsxImportSource ?? 'react';
const emit_css = options.emitCss ?? true;
const compile_options = { runtimeImports: options.runtimeImports };

/** @type {Map<string, string>} */
const css_cache = new Map();
Expand Down Expand Up @@ -118,7 +120,7 @@ export function tsrxReact(options = {}) {
if (!should_compile(options, args.path)) return undefined;

const source = await readFile(args.path, 'utf-8');
const { code, css } = compile(source, args.path);
const { code, css } = compile(source, args.path, compile_options);
const css_id = to_css_id(args.path);

let output = code;
Expand Down
19 changes: 19 additions & 0 deletions packages/bun-plugin-react/tests/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,25 @@ describe('@tsrx/bun-plugin-react', () => {
}
});

it('forwards direct runtime imports to the compiler', async () => {
const dir = await mkdtemp(path.join(os.tmpdir(), 'tsrx-bun-plugin-react-runtime-'));
try {
const file_path = path.join(dir, 'App.tsrx');
await writeFile(
file_path,
`export function App(props) @{
<input {...props} />
}`,
);

const hooks = setup_plugin({ runtimeImports: 'direct' });
const transformed = await load_tsrx(hooks, file_path);
expect(transformed?.contents).toContain("from '@tsrx/react-runtime/ref'");
} finally {
await rm(dir, { recursive: true, force: true });
}
});

it('honors exclude filters', async () => {
const hooks = setup_plugin({ exclude: /ignored\.tsrx$/ }, { target: 'browser' });
const transformed = await load_tsrx(hooks, '/project/ignored.tsrx');
Expand Down
1 change: 1 addition & 0 deletions packages/bun-plugin-react/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { BunPlugin } from 'bun';

export interface TsrxReactBunPluginOptions {
runtimeImports?: 'compiler' | 'direct';
include?: RegExp;
exclude?: RegExp | RegExp[];
jsxImportSource?: string;
Expand Down
4 changes: 3 additions & 1 deletion packages/bun-plugin-solid/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const CSS_QUERY_PATTERN = /\?tsrx-css&lang\.css$/;
* exclude?: RegExp | RegExp[],
* emitCss?: boolean,
* solid?: object,
* runtimeImports?: 'compiler' | 'direct',
* }} TsrxSolidBunPluginOptions
*/

Expand Down Expand Up @@ -99,6 +100,7 @@ async function transform_solid(source, file_path, solid_options) {
*/
export function tsrxSolid(options = {}) {
const emit_css = options.emitCss ?? true;
const compile_options = { runtimeImports: options.runtimeImports };

/** @type {Map<string, string>} */
const css_cache = new Map();
Expand All @@ -122,7 +124,7 @@ export function tsrxSolid(options = {}) {
if (!should_compile(options, args.path)) return undefined;

const source = await readFile(args.path, 'utf-8');
const { code, css } = compile(source, args.path);
const { code, css } = compile(source, args.path, compile_options);
const css_id = to_css_id(args.path);

let output = code;
Expand Down
19 changes: 19 additions & 0 deletions packages/bun-plugin-solid/tests/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,25 @@ describe('@tsrx/bun-plugin-solid', () => {
}
});

it('forwards direct runtime imports to the compiler', async () => {
const dir = await mkdtemp(path.join(os.tmpdir(), 'tsrx-bun-plugin-solid-runtime-'));
try {
const file_path = path.join(dir, 'App.tsrx');
await writeFile(
file_path,
`export function App(props) @{
<input {...props} />
}`,
);

const hooks = setup_plugin({ runtimeImports: 'direct' });
const transformed = await load_tsrx(hooks, file_path);
expect(transformed?.contents).toContain('@tsrx/solid-runtime/ref');
} finally {
await rm(dir, { recursive: true, force: true });
}
});

it('honors exclude filters', async () => {
const hooks = setup_plugin({ exclude: /ignored\.tsrx$/ }, { target: 'browser' });
const transformed = await load_tsrx(hooks, '/project/ignored.tsrx');
Expand Down
1 change: 1 addition & 0 deletions packages/bun-plugin-solid/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { BunPlugin } from 'bun';

export interface TsrxSolidBunPluginOptions {
runtimeImports?: 'compiler' | 'direct';
include?: RegExp;
exclude?: RegExp | RegExp[];
emitCss?: boolean;
Expand Down
4 changes: 3 additions & 1 deletion packages/bun-plugin-vue/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const DEFAULT_VAPOR_OPTIONS = {
* include?: RegExp,
* exclude?: RegExp | RegExp[],
* emitCss?: boolean,
* runtimeImports?: 'compiler' | 'direct',
* vapor?: {
* macros?: boolean | object,
* compiler?: { runtimeModuleName?: string },
Expand Down Expand Up @@ -128,6 +129,7 @@ function resolve_vapor_options(options) {
export function tsrxVue(options = {}) {
const emit_css = options.emitCss ?? true;
const vapor_options = resolve_vapor_options(options.vapor);
const compile_options = { runtimeImports: options.runtimeImports };

/** @type {Map<string, string>} */
const css_cache = new Map();
Expand Down Expand Up @@ -156,7 +158,7 @@ export function tsrxVue(options = {}) {
if (!should_compile(options, args.path)) return undefined;

const source = await readFile(args.path, 'utf-8');
const { code, css } = compile(source, args.path);
const { code, css } = compile(source, args.path, compile_options);
const css_id = to_css_id(args.path);

let output = code;
Expand Down
19 changes: 19 additions & 0 deletions packages/bun-plugin-vue/tests/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,25 @@ describe('@tsrx/bun-plugin-vue', () => {
}
});

it('forwards direct runtime imports to the compiler', async () => {
const dir = await mkdtemp(path.join(os.tmpdir(), 'tsrx-bun-plugin-vue-runtime-'));
try {
const file_path = path.join(dir, 'App.tsrx');
await writeFile(
file_path,
`export function App(props) @{
<input {...props} />
}`,
);

const hooks = setup_plugin({ runtimeImports: 'direct' });
const transformed = await load_tsrx(hooks, file_path);
expect(transformed?.contents).toContain('@tsrx/vue-runtime/ref');
} finally {
await rm(dir, { recursive: true, force: true });
}
});

it('honors exclude filters', async () => {
const hooks = setup_plugin({ exclude: /ignored\.tsrx$/ }, { target: 'browser' });
const transformed = await load_tsrx(hooks, '/project/ignored.tsrx');
Expand Down
1 change: 1 addition & 0 deletions packages/bun-plugin-vue/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface TsrxVueBunPluginVaporOptions {
}

export interface TsrxVueBunPluginOptions {
runtimeImports?: 'compiler' | 'direct';
include?: RegExp;
exclude?: RegExp | RegExp[];
emitCss?: boolean;
Expand Down
2 changes: 1 addition & 1 deletion packages/rspack-plugin-preact/src/css-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { compile } from '@tsrx/preact';
* the scoped CSS emitted by its `<style>` block. Invoked when rspack resolves
* the sibling `?tsrx-css&lang.css` import prepended by the JS loader.
*
* @this {LoaderContext<{ suspenseSource?: string }>}
* @this {LoaderContext<{ suspenseSource?: string, runtimeImports?: 'compiler' | 'direct' }>}
* @param {string} source
* @returns {void}
*/
Expand Down
5 changes: 4 additions & 1 deletion packages/rspack-plugin-preact/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ const CSS_QUERY_PATTERN = /tsrx-css/;
*/
export class TsrxPreactRspackPlugin {
/**
* @param {{ jsxImportSource?: string, suspenseSource?: string }} [options]
* @param {{ jsxImportSource?: string, suspenseSource?: string, runtimeImports?: 'compiler' | 'direct' }} [options]
*/
constructor(options = {}) {
this.options = {
jsxImportSource: options.jsxImportSource ?? 'preact',
suspenseSource: options.suspenseSource,
runtimeImports: options.runtimeImports ?? 'compiler',
};
}

Expand Down Expand Up @@ -85,6 +86,7 @@ export class TsrxPreactRspackPlugin {
loader: JS_LOADER,
options: {
suspenseSource: this.options.suspenseSource,
runtimeImports: this.options.runtimeImports,
},
},
],
Expand All @@ -98,6 +100,7 @@ export class TsrxPreactRspackPlugin {
loader: CSS_LOADER,
options: {
suspenseSource: this.options.suspenseSource,
runtimeImports: this.options.runtimeImports,
},
},
],
Expand Down
2 changes: 1 addition & 1 deletion packages/rspack-plugin-preact/src/js-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { compile } from '@tsrx/preact';
* prepends an `import` to the sibling virtual CSS module so rspack can
* include the styles in the asset graph.
*
* @this {LoaderContext<{ suspenseSource?: string }>}
* @this {LoaderContext<{ suspenseSource?: string, runtimeImports?: 'compiler' | 'direct' }>}
* @param {string} source
* @returns {void}
*/
Expand Down
4 changes: 3 additions & 1 deletion packages/rspack-plugin-preact/tests/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ describe('@tsrx/rspack-plugin-preact css-loader', () => {

describe('@tsrx/rspack-plugin-preact plugin', () => {
it('registers module rules for .tsrx and sibling css query', () => {
const plugin = new TsrxPreactRspackPlugin();
const plugin = new TsrxPreactRspackPlugin({ runtimeImports: 'direct' });
const compiler = {
options: {
module: { rules: [] },
Expand All @@ -158,9 +158,11 @@ describe('@tsrx/rspack-plugin-preact plugin', () => {
expect(jsRule.test.toString()).toContain('tsrx');
expect(jsRule.use).toHaveLength(2);
expect(jsRule.use[0].loader).toBe('builtin:swc-loader');
expect(jsRule.use[1].options.runtimeImports).toBe('direct');

expect(cssRule.resourceQuery.toString()).toContain('tsrx-css');
expect(cssRule.type).toBe('css/auto');
expect(cssRule.use[0].options.runtimeImports).toBe('direct');
});

it('respects a user-provided jsxImportSource', () => {
Expand Down
4 changes: 3 additions & 1 deletion packages/rspack-plugin-preact/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import type { Compiler, RspackPluginInstance } from '@rspack/core';
export interface TsrxPreactRspackPluginOptions {
jsxImportSource?: string;
suspenseSource?: string;
runtimeImports?: 'compiler' | 'direct';
}

export declare class TsrxPreactRspackPlugin implements RspackPluginInstance {
constructor(options?: TsrxPreactRspackPluginOptions);
options: Required<Pick<TsrxPreactRspackPluginOptions, 'jsxImportSource'>> &
Pick<TsrxPreactRspackPluginOptions, 'suspenseSource'>;
Pick<TsrxPreactRspackPluginOptions, 'suspenseSource'> &
Required<Pick<TsrxPreactRspackPluginOptions, 'runtimeImports'>>;
apply(compiler: Compiler): void;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/rspack-plugin-react/src/css-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { compile } from '@tsrx/react';
* the scoped CSS emitted by its `<style>` block. Invoked when rspack resolves
* the sibling `?tsrx-css&lang.css` import prepended by the JS loader.
*
* @this {LoaderContext<object>}
* @this {LoaderContext<{ runtimeImports?: 'compiler' | 'direct' }>}
* @param {string} source
* @returns {void}
*/
Expand All @@ -16,7 +16,7 @@ export default function cssLoader(source) {
const resourcePath = this.resourcePath;

try {
const { css } = compile(source, resourcePath);
const { css } = compile(source, resourcePath, this.getOptions?.());
callback(null, css);
} catch (/** @type {any} */ err) {
callback(err);
Expand Down
Loading