diff --git a/.changeset/sweet-waves-tell.md b/.changeset/sweet-waves-tell.md new file mode 100644 index 000000000..b6e8934e3 --- /dev/null +++ b/.changeset/sweet-waves-tell.md @@ -0,0 +1,5 @@ +--- +'houdini-adapter-auto': patch +--- + +Add smart adapter diff --git a/.changeset/ten-tips-mix.md b/.changeset/ten-tips-mix.md new file mode 100644 index 000000000..60fe4d2f3 --- /dev/null +++ b/.changeset/ten-tips-mix.md @@ -0,0 +1,5 @@ +--- +'houdini-adapter-node': patch +--- + +Add adapter for node diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f27217025..91abdae6d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -142,62 +142,6 @@ jobs: - name: Run init run: cd project && node ../houdini/packages/houdini/build/cmd-esm/index.js init -y - - verify_create: - name: Verify Create - runs-on: ubuntu-latest - strategy: - matrix: - template: [react, react-typescript, sveltekit-demo] - steps: - - name: Checkout source - uses: actions/checkout@v3 - with: - ref: ${{ github.ref }} - - - name: Install Node.js - uses: actions/setup-node@v3 - with: - node-version: 18.17.1 - - - uses: pnpm/action-setup@v2.0.1 - name: Install pnpm - id: pnpm-install - with: - version: 8 - - - name: Get pnpm store directory - id: pnpm-cache - run: | - echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" - - - uses: actions/cache@v3 - name: Setup pnpm cache - with: - path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - - name: Install dependencies - run: cd packages/create-houdini && pnpm install - - - name: Create template (local) - if: matrix.template != 'sveltekit-demo' - run: cd packages/create-houdini && pnpm dev test-${{ matrix.template }} -t ${{ matrix.template }} -s local - - - name: Create template (not local) - if: matrix.template == 'sveltekit-demo' - run: cd packages/create-houdini && pnpm dev test-${{ matrix.template }} -t ${{ matrix.template }} - - - run: cd packages/create-houdini/test-${{ matrix.template }} && npx playwright install - - - name: e2e install - run: cd packages/create-houdini/test-${{ matrix.template }} && npm i - - - name: e2e tests - if: matrix.template == 'sveltekit-demo' - run: cd packages/create-houdini/test-${{ matrix.template }} && npm run test:integration e2e_tests: name: End-to-End Tests @@ -314,4 +258,4 @@ jobs: run: pnpm --filter e2e-kit run lint - name: End-to-End check - run: pnpm --filter e2e-kit run check \ No newline at end of file + run: pnpm --filter e2e-kit run check diff --git a/e2e/react/package.json b/e2e/react/package.json index d0145947d..1c231d6ef 100644 --- a/e2e/react/package.json +++ b/e2e/react/package.json @@ -34,6 +34,7 @@ "cross-env": "^7.0.3", "e2e-api": "workspace:^", "hono": "^3.6.0", + "houdini-adapter-node": "workspace:^", "typescript": "^4.9.3", "vite": "^4.1.0", "wrangler": "^3.7.0" diff --git a/packages/adapter-auto/package.json b/packages/adapter-auto/package.json new file mode 100644 index 000000000..730a2ed84 --- /dev/null +++ b/packages/adapter-auto/package.json @@ -0,0 +1,55 @@ +{ + "name": "houdini-adapter-auto", + "version": "1.2.27", + "description": "An adapter for deploying your Houdini application according to the build environment ", + "keywords": [ + "houdini", + "adpter", + "cloudflare", + "workers", + "node" + ], + "homepage": "https://github.com/HoudiniGraphql/houdini", + "funding": "https://github.com/sponsors/HoudiniGraphql", + "repository": { + "type": "git", + "url": "https://github.com/HoudiniGraphql/houdini.git" + }, + "license": "MIT", + "type": "module", + "scripts": { + "build": "tsup src/* --format esm,cjs --external vite --minify --dts --clean --out-dir build", + "build:": "cd ../../ && ((run build && cd -) || (cd - && exit 1))", + "build:build": "pnpm build: && pnpm build" + }, + "devDependencies": { + "scripts": "workspace:^", + "tsup": "^7.2.0" + }, + "dependencies": { + "houdini": "workspace:^", + "import-meta-resolve": "^3.0.0" + }, + "files": [ + "build" + ], + "exports": { + "./package.json": "./package.json", + ".": { + "import": "./build/index.js", + "require": "./build/index.cjs" + }, + "./app": { + "import": "./build/app.js", + "require": "./build/app.cjs" + } + }, + "types": "./build/index.d.ts", + "typesVersions": { + "*": { + "app": [ + "build/app.d.ts" + ] + } + } +} diff --git a/packages/adapter-auto/src/index.ts b/packages/adapter-auto/src/index.ts new file mode 100644 index 000000000..1177847e6 --- /dev/null +++ b/packages/adapter-auto/src/index.ts @@ -0,0 +1,106 @@ +import { type Adapter, detectTools } from 'houdini' +import { resolve } from 'import-meta-resolve' +import { execSync } from 'node:child_process' +import { pathToFileURL } from 'node:url' + +const adapters = [ + { + name: 'CloudFlare Pages', + test: () => Boolean(process.env.CF_PAGES), + module: 'houdini-adapter-cloudflare', + }, + { + name: 'HoudiniCloud', + test: () => Boolean(process.env.HOUDINI_CLOUD), + module: 'houdini-cloud-adapter', + }, + // putting this at the bottom makes it will be the default + { + name: 'Node', + test: () => true, + module: 'houdini-adapter-node', + }, +] + +const adapter: Adapter = async (ctx) => { + // find the matching adapter + let match: (typeof adapters)[number] | undefined + for (const adapter of adapters) { + if (adapter.test()) { + match = adapter + break + } + } + + // make typescript happy even tho we have a default + if (!match) throw new Error('Could not identify environment') + + // tell the user what we found + console.log(`🎩 Identified environment: ${match.name}`) + + // load the adapter + const nextAdapter = await loadAdapter(match) + + // run the adapter + return nextAdapter(ctx) +} + +async function loadAdapter({ module }: { module: string }): Promise { + // if we have the required module loaded, we're good + try { + return (await importFromCwd(module)) as Adapter + } catch (err) { + // if the error indicates we were missing the module, let's keep going + const error = err as Error & { code: string } + if ( + error.code !== 'ERR_MODULE_NOT_FOUND' || + !error.message.startsWith(`Cannot find package '${module}'`) + ) { + throw err + } + } + + // if we didn't have the module loaded we can try installing it with the users package manager + const { package_manager } = await detectTools() + + // the command to run to install the adapter + const installCmds = { + yarn: 'add -D', + npm: 'install -D', + pnpm: 'add -D', + } + + // something might go wrong during installation + try { + // install the pacakge we need to + execSync(`${package_manager} ${installCmds[package_manager]} ${module}`, { + stdio: 'inherit', + env: { + ...process.env, + NODE_ENV: undefined, + }, + }) + + console.log(`Successfully installed ${module}!`) + console.warn( + `If you plan on staying in this environment, consider adding ${module} to your project so you don't have to install it every time you build your application.` + ) + + // we should be able to import it now + return (await importFromCwd(module)) as Adapter + } catch (err) { + throw new Error( + `Could not install package ${module}. Please install it manually or maybe consider replacing houdini-adapter-auto with ${module}.` + + `\n${(err as Error).message}` + ) + } +} + +async function importFromCwd(name: string) { + const cwd = pathToFileURL(process.cwd()).href + const url = resolve(name, cwd + '/x.js') + + return (await import(url)).default +} + +export default adapter diff --git a/packages/houdini-adapter-cloudflare/CHANGELOG.md b/packages/adapter-cloudflare/CHANGELOG.md similarity index 100% rename from packages/houdini-adapter-cloudflare/CHANGELOG.md rename to packages/adapter-cloudflare/CHANGELOG.md diff --git a/packages/houdini-adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json similarity index 72% rename from packages/houdini-adapter-cloudflare/package.json rename to packages/adapter-cloudflare/package.json index ba25aee84..e2f2b1a77 100644 --- a/packages/houdini-adapter-cloudflare/package.json +++ b/packages/adapter-cloudflare/package.json @@ -16,28 +16,18 @@ }, "license": "MIT", "type": "module", - "devDependencies": { - "@cloudflare/workers-types": "^4.20230904.0", - "@types/cookie": "^0.5.2", - "scripts": "workspace:^", - "tsup": "^7.2.0", - "vitest": "^0.28.3" - }, "scripts": { - "build": "tsup src/index.ts src/worker.ts --format esm,cjs --external vite --external ../\\$houdini --external ../src --external graphql --minify --dts --clean --out-dir build", + "build": "tsup src/index.ts src/worker.ts --format esm,cjs --minify --dts --clean --out-dir build", "build:": "cd ../../ && ((run build && cd -) || (cd - && exit 1))", "build:build": "pnpm build: && pnpm build" }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20230904.0", + "scripts": "workspace:^", + "tsup": "^7.2.0" + }, "dependencies": { - "@cloudflare/kv-asset-handler": "^0.3.0", - "@types/react": "^18.2.21", - "@types/react-dom": "^18.0.10", - "cookie": "^0.5.0", - "graphql-yoga": "^4.0.4", - "houdini": "workspace:^", - "itty-router": "^4.0.23", - "react": "^18.2.0", - "react-dom": "^18.2.0" + "houdini": "workspace:^" }, "files": [ "build" diff --git a/packages/houdini-adapter-cloudflare/src/index.ts b/packages/adapter-cloudflare/src/index.ts similarity index 50% rename from packages/houdini-adapter-cloudflare/src/index.ts rename to packages/adapter-cloudflare/src/index.ts index 880d430fd..ac42e8445 100644 --- a/packages/houdini-adapter-cloudflare/src/index.ts +++ b/packages/adapter-cloudflare/src/index.ts @@ -1,12 +1,13 @@ import { type Adapter, fs, path } from 'houdini' import { fileURLToPath } from 'node:url' -const adapter: Adapter = async ({ adapterPath, outDir, sourceDir }) => { - // the first thing we have to do is copy the source directory over - await fs.recursiveCopy(sourceDir, path.join(outDir, 'assets')) - +// the only thing we need to do for the cloudflare adapter is to copy the worker file +// to the dist directory +const adapter: Adapter = async ({ adapterPath, outDir }) => { // read the contents of the worker file - let workerContents = (await fs.readFile(sourcePath('./worker.js')))! + let workerContents = (await fs.readFile( + fileURLToPath(new URL('./worker.js', import.meta.url).href) + ))! // make sure that the adapter module imports from the correct path workerContents = workerContents.replaceAll('houdini/adapter', adapterPath) @@ -15,7 +16,3 @@ const adapter: Adapter = async ({ adapterPath, outDir, sourceDir }) => { } export default adapter - -function sourcePath(path: string) { - return fileURLToPath(new URL(path, import.meta.url).href) -} diff --git a/packages/houdini-adapter-cloudflare/src/worker.ts b/packages/adapter-cloudflare/src/worker.ts similarity index 100% rename from packages/houdini-adapter-cloudflare/src/worker.ts rename to packages/adapter-cloudflare/src/worker.ts diff --git a/packages/adapter-node/package.json b/packages/adapter-node/package.json new file mode 100644 index 000000000..8f4f5ec79 --- /dev/null +++ b/packages/adapter-node/package.json @@ -0,0 +1,48 @@ +{ + "name": "houdini-adapter-node", + "version": "1.2.27", + "description": "The adapter for deploying your Houdini application as a standalone node server", + "keywords": [ + "houdini", + "adpter", + "node" + ], + "homepage": "https://github.com/HoudiniGraphql/houdini", + "funding": "https://github.com/sponsors/HoudiniGraphql", + "repository": { + "type": "git", + "url": "https://github.com/HoudiniGraphql/houdini.git" + }, + "license": "MIT", + "type": "module", + "scripts": { + "build": "tsup src/index.ts src/app.ts --format esm,cjs --minify --dts --clean --out-dir build", + "build:": "cd ../../ && ((run build && cd -) || (cd - && exit 1))", + "build:build": "pnpm build: && pnpm build" + }, + "devDependencies": { + "scripts": "workspace:^", + "tsup": "^7.2.0" + }, + "dependencies": { + "houdini": "workspace:^" + }, + "files": [ + "build" + ], + "exports": { + "./package.json": "./package.json", + ".": { + "import": "./build/index.js", + "require": "./build/index.cjs" + } + }, + "types": "./build/index.d.ts", + "typesVersions": { + "*": { + "app": [ + "build/app.d.ts" + ] + } + } +} diff --git a/packages/adapter-node/src/app.ts b/packages/adapter-node/src/app.ts new file mode 100644 index 000000000..035935a89 --- /dev/null +++ b/packages/adapter-node/src/app.ts @@ -0,0 +1,14 @@ +import { createServerAdapter } from 'houdini/adapter' +import { createServer } from 'node:http' + +// create the production server adapter +const serverAdapter = createServerAdapter({ + production: true, + assetPrefix: '/assets', +}) + +// wrap the server adapter in a node http server +const nodeServer = createServer(serverAdapter) + +// start listening on the designated port +nodeServer.listen(process.env.PORT ?? 3000) diff --git a/packages/adapter-node/src/index.ts b/packages/adapter-node/src/index.ts new file mode 100644 index 000000000..56ec6fae4 --- /dev/null +++ b/packages/adapter-node/src/index.ts @@ -0,0 +1,16 @@ +import { type Adapter, fs, path } from 'houdini' +import { fileURLToPath } from 'node:url' + +const adapter: Adapter = async ({ outDir, adapterPath }) => { + // read the contents of the app file + let workerContents = (await fs.readFile( + fileURLToPath(new URL('./app.js', import.meta.url).href) + ))! + + // make sure that the adapter module imports from the correct path + workerContents = workerContents.replaceAll('houdini/adapter', adapterPath) + + await fs.writeFile(path.join(outDir, 'index.js'), workerContents!) +} + +export default adapter diff --git a/packages/create-houdini/templates/react-typescript/package.json b/packages/create-houdini/templates/react-typescript/package.json index b79fec5e4..d0f203aab 100644 --- a/packages/create-houdini/templates/react-typescript/package.json +++ b/packages/create-houdini/templates/react-typescript/package.json @@ -11,6 +11,7 @@ "dependencies": { "houdini": "^HOUDINI_VERSION", "houdini-react": "^HOUDINI_VERSION", + "houdini-adapter-auto": "^HOUDINI_VERSION", "react": "^18.2.0", "react-dom": "^18.2.0", "graphql-yoga": "4.0.4", diff --git a/packages/create-houdini/templates/react-typescript/vite.config.ts b/packages/create-houdini/templates/react-typescript/vite.config.ts index ea18f3b48..2ca691998 100644 --- a/packages/create-houdini/templates/react-typescript/vite.config.ts +++ b/packages/create-houdini/templates/react-typescript/vite.config.ts @@ -1,8 +1,9 @@ import react from '@vitejs/plugin-react' +import adapter from 'houdini-adapter-auto' import houdini from 'houdini/vite' import { defineConfig } from 'vite' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [houdini(), react({ fastRefresh: false })], + plugins: [houdini({ adapter }), react({ fastRefresh: false })], }) diff --git a/packages/create-houdini/templates/react/package.json b/packages/create-houdini/templates/react/package.json index 95f2439a1..e34f12e4a 100644 --- a/packages/create-houdini/templates/react/package.json +++ b/packages/create-houdini/templates/react/package.json @@ -11,6 +11,7 @@ "dependencies": { "houdini": "^HOUDINI_VERSION", "houdini-react": "^HOUDINI_VERSION", + "houdini-adapter-auto": "^HOUDINI_VERSION", "react": "^18.2.0", "react-dom": "^18.2.0", "graphql-yoga": "4.0.4", diff --git a/packages/create-houdini/templates/react/vite.config.ts b/packages/create-houdini/templates/react/vite.config.ts index ea18f3b48..2ca691998 100644 --- a/packages/create-houdini/templates/react/vite.config.ts +++ b/packages/create-houdini/templates/react/vite.config.ts @@ -1,8 +1,9 @@ import react from '@vitejs/plugin-react' +import adapter from 'houdini-adapter-auto' import houdini from 'houdini/vite' import { defineConfig } from 'vite' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [houdini(), react({ fastRefresh: false })], + plugins: [houdini({ adapter }), react({ fastRefresh: false })], }) diff --git a/packages/houdini/src/lib/detectTools.ts b/packages/houdini/src/lib/detectTools.ts index 830d85b5c..2709cc9d5 100644 --- a/packages/houdini/src/lib/detectTools.ts +++ b/packages/houdini/src/lib/detectTools.ts @@ -49,7 +49,7 @@ export async function detectFromPackageJSON(cwd: string): Promise { +export async function detectTools(cwd: string = process.cwd()): Promise { let typescript = false try { await fs.stat(path.join(cwd, 'tsconfig.json')) diff --git a/packages/houdini/src/vite/houdini.ts b/packages/houdini/src/vite/houdini.ts index 49b3a2e75..bdda86729 100644 --- a/packages/houdini/src/vite/houdini.ts +++ b/packages/houdini/src/vite/houdini.ts @@ -122,6 +122,9 @@ export default function Plugin(opts: PluginConfig = {}): VitePlugin { await fs.recursiveCopy(path.join(sourceDir, 'ssr'), path.join(outDir, 'ssr')) await fs.rmdir(path.join(sourceDir, 'ssr')) + // copy the asset directory into the build directory + await fs.recursiveCopy(sourceDir, path.join(outDir, 'assets')) + // invoke the adapter await opts.adapter({ config, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 188b81ee4..cb0a2f8e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -200,7 +200,7 @@ importers: version: link:../../packages/houdini houdini-adapter-cloudflare: specifier: workspace:^ - version: link:../../packages/houdini-adapter-cloudflare + version: link:../../packages/adapter-cloudflare houdini-react: specifier: workspace:^ version: link:../../packages/houdini-react @@ -232,6 +232,9 @@ importers: hono: specifier: ^3.6.0 version: 3.6.0 + houdini-adapter-node: + specifier: workspace:^ + version: link:../../packages/adapter-node typescript: specifier: ^4.9.3 version: 4.9.4 @@ -314,6 +317,51 @@ importers: specifier: ^4.9 version: 4.9.4 + packages/adapter-auto: + dependencies: + houdini: + specifier: workspace:^ + version: link:../houdini + import-meta-resolve: + specifier: ^3.0.0 + version: 3.0.0 + devDependencies: + scripts: + specifier: workspace:^ + version: link:../_scripts + tsup: + specifier: ^7.2.0 + version: 7.2.0(typescript@4.9.4) + + packages/adapter-cloudflare: + dependencies: + houdini: + specifier: workspace:^ + version: link:../houdini + devDependencies: + '@cloudflare/workers-types': + specifier: ^4.20230904.0 + version: 4.20230904.0 + scripts: + specifier: workspace:^ + version: link:../_scripts + tsup: + specifier: ^7.2.0 + version: 7.2.0(typescript@4.9.4) + + packages/adapter-node: + dependencies: + houdini: + specifier: workspace:^ + version: link:../houdini + devDependencies: + scripts: + specifier: workspace:^ + version: link:../_scripts + tsup: + specifier: ^7.2.0 + version: 7.2.0(typescript@4.9.4) + packages/create-houdini: dependencies: '@clack/prompts': @@ -448,52 +496,6 @@ importers: specifier: ^0.28.3 version: 0.28.3(@vitest/ui@0.28.3) - packages/houdini-adapter-cloudflare: - dependencies: - '@cloudflare/kv-asset-handler': - specifier: ^0.3.0 - version: 0.3.0 - '@types/react': - specifier: ^18.2.21 - version: 18.2.21 - '@types/react-dom': - specifier: ^18.0.10 - version: 18.0.11 - cookie: - specifier: ^0.5.0 - version: 0.5.0 - graphql-yoga: - specifier: ^4.0.4 - version: 4.0.4(graphql@15.5.0) - houdini: - specifier: workspace:^ - version: link:../houdini - itty-router: - specifier: ^4.0.23 - version: 4.0.23 - react: - specifier: ^18.2.0 - version: 18.2.0 - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - devDependencies: - '@cloudflare/workers-types': - specifier: ^4.20230904.0 - version: 4.20230904.0 - '@types/cookie': - specifier: ^0.5.2 - version: 0.5.2 - scripts: - specifier: workspace:^ - version: link:../_scripts - tsup: - specifier: ^7.2.0 - version: 7.2.0(typescript@4.9.4) - vitest: - specifier: ^0.28.3 - version: 0.28.3(@vitest/ui@0.28.3) - packages/houdini-plugin-svelte-global-stores: dependencies: '@sveltejs/kit': @@ -1501,12 +1503,6 @@ packages: mime: 3.0.0 dev: true - /@cloudflare/kv-asset-handler@0.3.0: - resolution: {integrity: sha512-9CB/MKf/wdvbfkUdfrj+OkEwZ5b7rws0eogJ4293h+7b6KX5toPwym+VQKmILafNB9YiehqY0DlNrDcDhdWHSQ==} - dependencies: - mime: 3.0.0 - dev: false - /@cloudflare/workerd-darwin-64@1.20230904.0: resolution: {integrity: sha512-/GDlmxAFbDtrQwP4zOXFbqOfaPvkDxdsCoEa+KEBcAl5uR98+7WW5/b8naBHX+t26uS7p4bLlImM8J5F1ienRQ==} engines: {node: '>=16'} @@ -3191,6 +3187,7 @@ packages: resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==} dependencies: '@types/react': 18.2.21 + dev: true /@types/react@18.0.33: resolution: {integrity: sha512-sHxzVxeanvQyQ1lr8NSHaj0kDzcNiGpILEVt69g9S31/7PfMvNCKLKcsHw4lYKjs3cGNJjXSP4mYzX43QlnjNA==} @@ -3214,6 +3211,7 @@ packages: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 csstype: 3.1.1 + dev: true /@types/sass@1.43.1: resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==} @@ -7123,6 +7121,10 @@ packages: /import-meta-resolve@2.2.0: resolution: {integrity: sha512-CpPOtiCHxP9HdtDM5F45tNiAe66Cqlv3f5uHoJjt+KlaLrUh9/Wz9vepADZ78SlqEo62aDWZtj9ydMGXV+CPnw==} + /import-meta-resolve@3.0.0: + resolution: {integrity: sha512-4IwhLhNNA8yy445rPjD/lWh++7hMDOml2eHtd58eG7h+qK3EryMuuRbsHGPikCoAgIkkDnckKfWSk2iDla/ejg==} + dev: false + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -7470,10 +7472,6 @@ packages: istanbul-lib-report: 3.0.0 dev: true - /itty-router@4.0.23: - resolution: {integrity: sha512-tP1NI8PVK43vWlBnIPqj47ni5FDSczFviA4wgBznscndo8lEvBA+pO3DD1rNbIQPcZhprr775iUTunyGvQMcBw==} - dev: false - /javascript-natural-sort@0.7.1: resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} dev: true diff --git a/site/src/routes/api/react/+page.svx b/site/src/routes/api/react/+page.svx index ef9816354..65f4be2c0 100644 --- a/site/src/routes/api/react/+page.svx +++ b/site/src/routes/api/react/+page.svx @@ -20,6 +20,9 @@ is not organized as an introduction but more of a reference. Don't worry - there Houdini's React bindings are still considered unstable and are subject to change with every patch update (the third number). If you are building stuff with it, please check the changelog for any updates or pin to a specific version. +We recommend installing the `@canary` tag which will give you the latest version merged to `main` and might include fixes that +haven't yet been deployed. + ## What is Houdini? @@ -384,3 +387,5 @@ export default config Here is a list of the available adapters: - `houdini-adapter-cloudflare`: builds your application to run on Cloudflare Pages +- `houdini-adapter-node`: builds your application to run as a standalone node process +- `houdini-adapter-auto`: tries to install the appropriate adapter for the current situation