This guide covers how to set up aisx in different environments.
For projects that don't use React or other JSX libraries, this is the simplest and most reliable setup.
-
Install the package:
# Using npm npm install aisx # Using yarn yarn add aisx # Using pnpm pnpm add aisx # Using bun bun add aisx
-
Configure
tsconfig.jsonby extending aisx's provided configuration:{ "extends": "aisx/tsconfig/aisx", "compilerOptions": { // Your additional compiler options "moduleResolution": "bundler", "target": "ESNext", "module": "ESNext", "allowImportingTsExtensions": true, "noEmit": true }, "include": [ "./**/*.ts", "./**/*.tsx" ] } -
Create a type declaration file
aisx.d.tsto ensure TypeScript recognizes aisx JSX:/// <reference types="aisx/types/global" /> -
For Bun users, add the following to your
bunfig.toml:# JSX settings for aisx files jsxImportSource = "aisx" # File-specific loaders [loader] ".tsx" = "tsx" ".aisx.tsx" = "tsx" ".aisx.test.tsx" = "tsx"
-
Create a
.aisx.tsxfile:/** @jsxImportSource aisx */ import aisx from "aisx" export function Greeting(props: { name: string }) { return ( <greeting> Hello, {props.name}! </greeting> ) }
-
Import and use it:
import { Greeting } from "./greeting.aisx.tsx" // Function call approach (simplest) const greeting = Greeting({ name: "world" }) console.log(greeting) // JSX approach (requires JSX support in your project) import aisx from "aisx" // For regular components const jsxGreeting = <Greeting name="world" /> console.log(jsxGreeting) // For async components const asyncResult = await aisx.render(<AsyncComponent prop="value" />) console.log(asyncResult)
If you prefer not to modify global TypeScript settings, you can use a JSX pragma at the top of each aisx file:
/** @jsxImportSource aisx */
export function Greeting(props: { name: string }) {
return (
<greeting>
Hello, {props.name}!
</greeting>
)
}aisx fully supports async components, which are particularly useful for dynamic content generation:
/** @jsxImportSource aisx */
// Async component that fetches data
export async function DynamicPrompt(props: { userId: string }) {
const userData = await fetchUserData(props.userId)
return (
<instruction>
You are assisting {userData.name} who is interested in {userData.interests.join(', ')}.
Please tailor your responses accordingly.
</instruction>
)
}
// Usage options:
// 1. Await the JSX expression
const dynamicPrompt = await <DynamicPrompt userId="123" />
// 2. Use the render function (recommended for complex cases)
import aisx from "aisx"
const renderedPrompt = await aisx.render(<DynamicPrompt userId="123" />)
// 3. Direct function call (returns a Promise)
const directPrompt = await DynamicPrompt({ userId: "123" })Running aisx alongside React in the same project is not recommended due to JSX runtime conflicts. However, if you must do this, the following configurations might help.
-
Create
tsconfig.aisx.json:{ "extends": "./tsconfig.json", "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "aisx" }, "include": ["**/*.aisx.tsx"] } -
Configure your build tool to use the appropriate tsconfig for each file type.
For Next.js, configure aisx in your next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: (config, { isServer }) => {
// Add .aisx.tsx support
config.module.rules.push({
test: /\.aisx\.tsx$/,
use: {
loader: 'babel-loader',
options: {
presets: ['next/babel'],
plugins: [
['@babel/plugin-transform-react-jsx', {
runtime: 'automatic',
importSource: 'aisx'
}]
]
}
}
});
return config;
}
};
module.exports = nextConfig;For Vite, create a plugin in vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { createFilter } from '@rollup/pluginutils';
export default defineConfig({
plugins: [
// Regular React plugin for .tsx files
react(),
// Custom plugin for .aisx.tsx files
{
name: 'vite-plugin-aisx',
transform(code, id) {
const filter = createFilter('**/*.aisx.tsx');
if (filter(id)) {
return {
code,
map: null,
customTransformCache: {
jsx: 'automatic',
jsxImportSource: 'aisx'
}
};
}
}
}
]
});aisx allows you to define custom JSX elements by extending the JSX namespace in your declaration files:
// custom.d.ts
declare namespace JSX {
interface IntrinsicElements {
// Add your custom elements
custom_element: Record<string, unknown>
another_element: {
required_prop: string
optional_prop?: number
}
}
}When you need to return multiple elements without a wrapper:
import aisx from "aisx"
export function MultipleElements() {
return (
<aisx.Fragment>
<first_element>First content</first_element>
<second_element>Second content</second_element>
</aisx.Fragment>
)
}Build complex templates through composition:
function Header({ title }: { title: string }) {
return <header>{title}</header>
}
function Body({ content }: { content: string }) {
return <body>{content}</body>
}
export function Document({ title, content }: { title: string; content: string }) {
return (
<document>
<Header title={title} />
<Body content={content} />
</document>
)
}-
JSX transpilation errors: Ensure your build system is correctly configured to process .aisx.tsx files.
-
Wrong JSX runtime used: Check that the
jsxImportSourceis correctly set to "aisx" for .aisx.tsx files. -
Type errors with JSX: Add reference directives to your declaration file:
/// <reference types="aisx" /> /// <reference types="aisx/types/global" />
-
Async component issues: Make sure you're properly awaiting the result when using async components.
// Correct const result = await <AsyncComponent /> // or const result = await aisx.render(<AsyncComponent />) // Incorrect - this will return a Promise const result = <AsyncComponent />
If you're using Node.js without TypeScript, you'll need a transpiler like Babel:
// babel.config.js
module.exports = {
presets: ['@babel/preset-env'],
plugins: [
['@babel/plugin-transform-react-jsx', {
runtime: 'automatic',
importSource: 'aisx'
}]
]
};For Deno, use the JSX pragma:
/** @jsxImportSource aisx */
export function Template() {
return <div>Hello from Deno</div>;
}For more information and examples, please see: