From 8af6c3627c8ca9847fd30dffa7f4b7dff873d627 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Sat, 17 Feb 2024 18:49:33 +0100 Subject: [PATCH 1/8] feat: improve configure hook --- bin/test.ts | 3 +- configure.ts | 82 +++++++++++++++++++++++--------- stubs/config.stub | 2 +- stubs/react/app.tsx.stub | 25 ++++++++++ stubs/react/root.edge.stub | 22 +++++++++ stubs/react/tsconfig.json.stub | 25 ++++++++++ stubs/solid/app.tsx.stub | 24 ++++++++++ stubs/solid/root.edge.stub | 21 +++++++++ stubs/solid/tsconfig.json.stub | 26 ++++++++++ stubs/vue/app.ts.stub | 27 +++++++++++ stubs/vue/root.edge.stub | 21 +++++++++ stubs/vue/tsconfig.json.stub | 26 ++++++++++ tests/configure.spec.ts | 86 +++++++++++++++++++++++++++------- tests_helpers/index.ts | 2 + 14 files changed, 351 insertions(+), 41 deletions(-) create mode 100644 stubs/react/app.tsx.stub create mode 100644 stubs/react/root.edge.stub create mode 100644 stubs/react/tsconfig.json.stub create mode 100644 stubs/solid/app.tsx.stub create mode 100644 stubs/solid/root.edge.stub create mode 100644 stubs/solid/tsconfig.json.stub create mode 100644 stubs/vue/app.ts.stub create mode 100644 stubs/vue/root.edge.stub create mode 100644 stubs/vue/tsconfig.json.stub diff --git a/bin/test.ts b/bin/test.ts index 63ce363..db85b8a 100644 --- a/bin/test.ts +++ b/bin/test.ts @@ -2,6 +2,7 @@ import { assert } from '@japa/assert' import { processCLIArgs, configure, run } from '@japa/runner' import { fileSystem } from '@japa/file-system' import { expectTypeOf } from '@japa/expect-type' +import { BASE_URL } from '../tests_helpers/index.js' /* |-------------------------------------------------------------------------- @@ -19,7 +20,7 @@ import { expectTypeOf } from '@japa/expect-type' processCLIArgs(process.argv.slice(2)) configure({ files: ['tests/**/*.spec.ts'], - plugins: [assert(), fileSystem(), expectTypeOf()], + plugins: [assert(), fileSystem({ basePath: BASE_URL }), expectTypeOf()], }) /* diff --git a/configure.ts b/configure.ts index cd35678..587b125 100644 --- a/configure.ts +++ b/configure.ts @@ -9,28 +9,37 @@ import type Configure from '@adonisjs/core/commands/configure' import { stubsRoot } from './stubs/main.js' +import { Codemods } from '@adonisjs/core/ace/codemods' -const ADAPTERS = ['Vue 3', 'React', 'Svelte'] as const +const ADAPTERS = ['Vue 3', 'React', 'Svelte', 'Solid'] as const const ADAPTERS_INFO: { [K in (typeof ADAPTERS)[number]]: { - dependencies: { - name: string - isDevDependency: boolean - }[] - ssrDependencies?: { - name: string - isDevDependency: boolean - }[] + stubFolder: string + extension: string + dependencies: { name: string; isDevDependency: boolean }[] + ssrDependencies?: { name: string; isDevDependency: boolean }[] + viteRegister: { + pluginCall: Parameters[0] + importDeclarations: Parameters[1] + } } } = { 'Vue 3': { + stubFolder: 'vue', + extension: 'ts', dependencies: [ { name: '@inertiajs/vue3', isDevDependency: false }, { name: 'vue', isDevDependency: false }, { name: '@vitejs/plugin-vue', isDevDependency: true }, ], + viteRegister: { + pluginCall: 'vue()', + importDeclarations: [{ isNamed: true, module: '@vitejs/plugin-vue', identifier: 'vue' }], + }, }, 'React': { + stubFolder: 'react', + extension: 'tsx', dependencies: [ { name: '@inertiajs/react', isDevDependency: false }, { name: 'react', isDevDependency: false }, @@ -39,13 +48,38 @@ const ADAPTERS_INFO: { { name: '@types/react', isDevDependency: true }, { name: '@types/react-dom', isDevDependency: true }, ], + viteRegister: { + pluginCall: 'react()', + importDeclarations: [{ isNamed: true, module: '@vitejs/plugin-react', identifier: 'react' }], + }, }, 'Svelte': { + stubFolder: 'svelte', + extension: 'ts', dependencies: [ { name: '@inertiajs/svelte', isDevDependency: false }, { name: 'svelte', isDevDependency: false }, { name: '@sveltejs/vite-plugin-svelte', isDevDependency: true }, ], + viteRegister: { + pluginCall: 'svelte()', + importDeclarations: [ + { isNamed: true, module: '@sveltejs/vite-plugin-svelte', identifier: 'svelte' }, + ], + }, + }, + 'Solid': { + stubFolder: 'solid', + extension: 'tsx', + dependencies: [ + { name: 'solid-js', isDevDependency: false }, + { name: 'inertia-adapter-solid', isDevDependency: false }, + { name: 'vite-plugin-solid', isDevDependency: true }, + ], + viteRegister: { + pluginCall: 'solid()', + importDeclarations: [{ isNamed: true, module: 'vite-plugin-solid', identifier: 'solid' }], + }, }, } @@ -61,19 +95,8 @@ export async function configure(command: Configure) { ADAPTERS, { name: 'adapter' } ) - const pkgToInstall = ADAPTERS_INFO[adapter].dependencies - - /** - * Prompt for SSR - */ - const withSsr = await command.prompt.confirm('Do you want to enable server-side rendering?', { - name: 'ssr', - }) - - if (withSsr) { - pkgToInstall.push(...(ADAPTERS_INFO[adapter].ssrDependencies || [])) - } + const adapterInfo = ADAPTERS_INFO[adapter] const codemods = await command.createCodemods() /** @@ -91,13 +114,28 @@ export async function configure(command: Configure) { ]) /** - * Publish config + * Publish stubs */ + const extension = adapterInfo.extension + const stubFolder = adapterInfo.stubFolder + await codemods.makeUsingStub(stubsRoot, 'config.stub', {}) + await codemods.makeUsingStub(stubsRoot, `${stubFolder}/root.edge.stub`, {}) + await codemods.makeUsingStub(stubsRoot, `${stubFolder}/tsconfig.json.stub`, {}) + await codemods.makeUsingStub(stubsRoot, `${stubFolder}/app.${extension}.stub`, {}) + + /** + * Update vite config + */ + await codemods.registerVitePlugin( + adapterInfo.viteRegister.pluginCall, + adapterInfo.viteRegister.importDeclarations + ) /** * Install packages */ + const pkgToInstall = adapterInfo.dependencies const shouldInstallPackages = await command.prompt.confirm( `Do you want to install dependencies ${pkgToInstall.map((pkg) => pkg.name).join(', ')}?`, { name: 'install' } diff --git a/stubs/config.stub b/stubs/config.stub index 4e7e37b..c27d7c1 100644 --- a/stubs/config.stub +++ b/stubs/config.stub @@ -7,7 +7,7 @@ export default defineConfig({ /** * Path to the Edge view that will be used as the root view for Inertia responses */ - rootView: 'home', + rootView: 'root', /** * Data that should be shared with all rendered pages diff --git a/stubs/react/app.tsx.stub b/stubs/react/app.tsx.stub new file mode 100644 index 0000000..fc66742 --- /dev/null +++ b/stubs/react/app.tsx.stub @@ -0,0 +1,25 @@ +{{{ + exports({ to: app.makePath('resources/app.tsx') }) +}}} +import './css/app.css'; + +import { createRoot } from 'react-dom/client'; +import { createInertiaApp } from '@inertiajs/react'; + +const appName = import.meta.env.VITE_APP_NAME || 'AdonisJS' + +createInertiaApp({ + progress: { color: '#5468FF' }, + + title: (title) => {{ '`${title} - ${appName}`' }}, + + resolve: (name) => { + const pages = import.meta.glob('./pages/**/*.vue', { eager: true }) + {{ 'return pages[`./pages/${name}.vue`]' }} + }, + + setup({ el, App, props }) { + const root = createRoot(el); + root.render(); + }, +}); diff --git a/stubs/react/root.edge.stub b/stubs/react/root.edge.stub new file mode 100644 index 0000000..661f400 --- /dev/null +++ b/stubs/react/root.edge.stub @@ -0,0 +1,22 @@ +{{{ + exports({ to: app.makePath('resources/views/root.edge') }) +}}} + + + + + + + + AdonisJS x Inertia x React + + @viteReactRefresh() + @vite(['resources/app.tsx']) + @inertiaHead() + + + + @inertia() + + + diff --git a/stubs/react/tsconfig.json.stub b/stubs/react/tsconfig.json.stub new file mode 100644 index 0000000..8ebf174 --- /dev/null +++ b/stubs/react/tsconfig.json.stub @@ -0,0 +1,25 @@ +{{{ + exports({ to: app.makePath('resources/tsconfig.json') }) +}}} +{ + "compilerOptions": { + "target": "ESNext", + "jsx": "react-jsx", + "lib": ["DOM", "ESNext", "DOM.Iterable", "ES2020"], + "useDefineForClassFields": true, + "baseUrl": ".", + "module": "ESNext", + "moduleResolution": "Bundler", + "paths": { + "@/*": ["./*"], + "~/*": ["../*"], + }, + "resolveJsonModule": true, + "types": ["vite/client"], + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true, + }, + "include": ["./**/*.ts", "./**/*.tsx", "app.tsx.stub"], +} diff --git a/stubs/solid/app.tsx.stub b/stubs/solid/app.tsx.stub new file mode 100644 index 0000000..4df4888 --- /dev/null +++ b/stubs/solid/app.tsx.stub @@ -0,0 +1,24 @@ +{{{ + exports({ to: app.makePath('resources/app.tsx') }) +}}} +import './css/app.css' + +import { render } from 'solid-js/web' +import { createInertiaApp } from 'inertia-adapter-solid' + +const appName = import.meta.env.VITE_APP_NAME || 'AdonisJS' + +createInertiaApp({ + progress: { color: '#5468FF' }, + + title: (title) => {{ '`${title} - ${appName}`' }}, + + resolve(name) { + const pages = import.meta.glob('./pages/**/*.tsx', { eager: true }) + {{ 'return pages[`./pages/${name}.tsx`]' }} + }, + + setup({ el, App, props }) { + render(() => , el) + }, +}) diff --git a/stubs/solid/root.edge.stub b/stubs/solid/root.edge.stub new file mode 100644 index 0000000..ed65297 --- /dev/null +++ b/stubs/solid/root.edge.stub @@ -0,0 +1,21 @@ +{{{ + exports({ to: app.makePath('resources/views/root.edge') }) +}}} + + + + + + + + AdonisJS x Inertia x SolidJS + + @vite(['resources/app.tsx']) + @inertiaHead() + + + + @inertia() + + + diff --git a/stubs/solid/tsconfig.json.stub b/stubs/solid/tsconfig.json.stub new file mode 100644 index 0000000..e1da785 --- /dev/null +++ b/stubs/solid/tsconfig.json.stub @@ -0,0 +1,26 @@ +{{{ + exports({ to: app.makePath('resources/tsconfig.json') }) +}}} +{ + "compilerOptions": { + "target": "ESNext", + "jsx": "preserve", + "jsxImportSource": "solid-js", + "lib": ["DOM", "ESNext", "DOM.Iterable", "ES2020"], + "useDefineForClassFields": true, + "baseUrl": ".", + "module": "ESNext", + "moduleResolution": "Bundler", + "paths": { + "@/*": ["./*"], + "~/*": ["../*"], + }, + "resolveJsonModule": true, + "types": ["vite/client"], + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true, + }, + "include": ["./**/*.ts", "./**/*.tsx", "app.tsx.stub"], +} diff --git a/stubs/vue/app.ts.stub b/stubs/vue/app.ts.stub new file mode 100644 index 0000000..a2c4549 --- /dev/null +++ b/stubs/vue/app.ts.stub @@ -0,0 +1,27 @@ +{{{ + exports({ to: app.makePath('resources/app.ts') }) +}}} +import './css/app.css'; + +import { createApp, h } from 'vue' +import type { DefineComponent } from 'vue' +import { createInertiaApp } from '@inertiajs/vue3' + +const appName = import.meta.env.VITE_APP_NAME || 'AdonisJS' + +createInertiaApp({ + progress: { color: '#5468FF' }, + + title: (title) => {{ '`${title} - ${appName}`' }}, + + resolve: (name) => { + const pages = import.meta.glob('./pages/**/*.vue', { eager: true }) + {{ 'return pages[`./pages/${name}.vue`]' }} + }, + + setup({ el, App, props, plugin }) { + createApp({ render: () => h(App, props) }) + .use(plugin) + .mount(el) + }, +}) diff --git a/stubs/vue/root.edge.stub b/stubs/vue/root.edge.stub new file mode 100644 index 0000000..2c4f9ae --- /dev/null +++ b/stubs/vue/root.edge.stub @@ -0,0 +1,21 @@ +{{{ + exports({ to: app.makePath('resources/views/root.edge') }) +}}} + + + + + + + + AdonisJS x Inertia x VueJS + + @vite(['resources/app.ts']) + @inertiaHead() + + + + @inertia() + + + diff --git a/stubs/vue/tsconfig.json.stub b/stubs/vue/tsconfig.json.stub new file mode 100644 index 0000000..9157ced --- /dev/null +++ b/stubs/vue/tsconfig.json.stub @@ -0,0 +1,26 @@ +{{{ + exports({ to: app.makePath('resources/tsconfig.json') }) +}}} +{ + "compilerOptions": { + "target": "ESNext", + "jsx": "preserve", + "jsxImportSource": "vue", + "lib": ["DOM", "ESNext", "DOM.Iterable", "ES2020"], + "useDefineForClassFields": true, + "baseUrl": ".", + "module": "ESNext", + "moduleResolution": "Bundler", + "paths": { + "@/*": ["./*"], + "~/*": ["../*"], + }, + "resolveJsonModule": true, + "types": ["vite/client"], + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true, + }, + "include": ["./**/*.ts", "./**/*.vue"], +} diff --git a/tests/configure.spec.ts b/tests/configure.spec.ts index ff2a7b9..e428cea 100644 --- a/tests/configure.spec.ts +++ b/tests/configure.spec.ts @@ -8,11 +8,10 @@ */ import { test } from '@japa/runner' -import { fileURLToPath } from 'node:url' import { IgnitorFactory } from '@adonisjs/core/factories' import Configure from '@adonisjs/core/commands/configure' - -const BASE_URL = new URL('./tmp/', import.meta.url) +import { BASE_URL } from '../tests_helpers/index.js' +import { FileSystem } from '@japa/file-system' async function setupApp() { const ignitor = new IgnitorFactory() @@ -37,17 +36,13 @@ async function setupApp() { return { ace, app } } -test.group('Configure', (group) => { - group.tap((t) => t.timeout(20_000)) - - group.each.setup(async ({ context }) => { - context.fs.baseUrl = BASE_URL - context.fs.basePath = fileURLToPath(BASE_URL) - - await context.fs.create('.env', '') - await context.fs.createJson('tsconfig.json', {}) - await context.fs.create('adonisrc.ts', `export default defineConfig({})`) - await context.fs.create( +async function setupFakeAdonisproject(fs: FileSystem) { + await Promise.all([ + fs.create('.env', ''), + fs.createJson('tsconfig.json', {}), + fs.create('adonisrc.ts', `export default defineConfig({})`), + fs.create('vite.config.ts', `export default { plugins: [] }`), + fs.create( 'start/kernel.ts', ` import router from '@adonisjs/core/services/router' @@ -60,14 +55,18 @@ test.group('Configure', (group) => { () => import('@adonisjs/auth/initialize_auth_middleware'), ]) ` - ) - }) + ), + ]) +} + +test.group('Configure', (group) => { + group.tap((t) => t.timeout(20_000)) + group.each.setup(async ({ context }) => setupFakeAdonisproject(context.fs)) test('add provider, config file, and middleware', async ({ assert }) => { const { ace } = await setupApp() ace.prompt.trap('adapter').replyWith('Vue 3') - ace.prompt.trap('ssr').reject() ace.prompt.trap('install').reject() const command = await ace.create(Configure, ['../../index.js']) @@ -79,3 +78,56 @@ test.group('Configure', (group) => { await assert.fileContains('start/kernel.ts', '@adonisjs/inertia/inertia_middleware') }) }) + +test.group('Frameworks', (group) => { + group.tap((t) => t.timeout(20_000)) + group.each.setup(async ({ context }) => setupFakeAdonisproject(context.fs)) + + test('Vue 3', async ({ assert, fs }) => { + await fs.createJson('package.json', {}) + await fs.createJson('tsconfig.json', { compilerOptions: {} }) + + const { ace } = await setupApp() + + ace.prompt.trap('adapter').replyWith('Vue 3') + ace.prompt.trap('install').reject() + + const command = await ace.create(Configure, ['../../index.js']) + await command.exec() + + await assert.fileExists('resources/app.ts') + await assert.fileExists('resources/views/root.edge') + await assert.fileExists('resources/tsconfig.json') + await assert.fileContains('vite.config.ts', '@vitejs/plugin-vue') + }) + + test('React', async ({ assert }) => { + const { ace } = await setupApp() + + ace.prompt.trap('adapter').replyWith('React') + ace.prompt.trap('install').reject() + + const command = await ace.create(Configure, ['../../index.js']) + await command.exec() + + await assert.fileExists('resources/app.tsx') + await assert.fileExists('resources/views/root.edge') + await assert.fileExists('resources/tsconfig.json') + await assert.fileContains('vite.config.ts', '@vitejs/plugin-react') + }) + + test('Solid', async ({ assert }) => { + const { ace } = await setupApp() + + ace.prompt.trap('adapter').replyWith('Solid') + ace.prompt.trap('install').reject() + + const command = await ace.create(Configure, ['../../index.js']) + await command.exec() + + await assert.fileExists('resources/app.tsx') + await assert.fileExists('resources/views/root.edge') + await assert.fileExists('resources/tsconfig.json') + await assert.fileContains('vite.config.ts', 'vite-plugin-solid') + }) +}) diff --git a/tests_helpers/index.ts b/tests_helpers/index.ts index 8acde1c..bdf6844 100644 --- a/tests_helpers/index.ts +++ b/tests_helpers/index.ts @@ -10,6 +10,8 @@ import { NamedReporterContract } from '@japa/runner/types' import { runner, syncReporter } from '@japa/runner/factories' import { inertiaApiClient } from '../src/plugins/api_client.js' +export const BASE_URL = new URL('./tmp/', import.meta.url) + /** * Create a http server that will be closed automatically * when the test ends From 6d82cdcbb7b828ceceb6b521199d22858ec38e7b Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Sun, 18 Feb 2024 01:26:38 +0100 Subject: [PATCH 2/8] feat: add more stub configuration --- configure.ts | 68 ++++++++++++++++++++++++++++++++------- stubs/app.css.stub | 39 ++++++++++++++++++++++ stubs/react/app.tsx.stub | 4 +-- stubs/react/home.tsx.stub | 21 ++++++++++++ stubs/solid/home.tsx.stub | 21 ++++++++++++ stubs/vue/home.vue.stub | 21 ++++++++++++ tests/configure.spec.ts | 40 ++++++++++++++++++++++- 7 files changed, 200 insertions(+), 14 deletions(-) create mode 100644 stubs/app.css.stub create mode 100644 stubs/react/home.tsx.stub create mode 100644 stubs/solid/home.tsx.stub create mode 100644 stubs/vue/home.vue.stub diff --git a/configure.ts b/configure.ts index 587b125..e1f571f 100644 --- a/configure.ts +++ b/configure.ts @@ -8,14 +8,16 @@ */ import type Configure from '@adonisjs/core/commands/configure' -import { stubsRoot } from './stubs/main.js' import { Codemods } from '@adonisjs/core/ace/codemods' +import { stubsRoot } from './stubs/main.js' + const ADAPTERS = ['Vue 3', 'React', 'Svelte', 'Solid'] as const const ADAPTERS_INFO: { [K in (typeof ADAPTERS)[number]]: { stubFolder: string - extension: string + appExtension: string + componentsExtension: string dependencies: { name: string; isDevDependency: boolean }[] ssrDependencies?: { name: string; isDevDependency: boolean }[] viteRegister: { @@ -26,7 +28,8 @@ const ADAPTERS_INFO: { } = { 'Vue 3': { stubFolder: 'vue', - extension: 'ts', + appExtension: 'ts', + componentsExtension: 'vue', dependencies: [ { name: '@inertiajs/vue3', isDevDependency: false }, { name: 'vue', isDevDependency: false }, @@ -39,7 +42,8 @@ const ADAPTERS_INFO: { }, 'React': { stubFolder: 'react', - extension: 'tsx', + appExtension: 'tsx', + componentsExtension: 'tsx', dependencies: [ { name: '@inertiajs/react', isDevDependency: false }, { name: 'react', isDevDependency: false }, @@ -55,7 +59,8 @@ const ADAPTERS_INFO: { }, 'Svelte': { stubFolder: 'svelte', - extension: 'ts', + appExtension: 'ts', + componentsExtension: 'svelte', dependencies: [ { name: '@inertiajs/svelte', isDevDependency: false }, { name: 'svelte', isDevDependency: false }, @@ -70,11 +75,13 @@ const ADAPTERS_INFO: { }, 'Solid': { stubFolder: 'solid', - extension: 'tsx', + appExtension: 'tsx', + componentsExtension: 'tsx', dependencies: [ { name: 'solid-js', isDevDependency: false }, { name: 'inertia-adapter-solid', isDevDependency: false }, { name: 'vite-plugin-solid', isDevDependency: true }, + { name: '@solidjs/meta', isDevDependency: false }, ], viteRegister: { pluginCall: 'solid()', @@ -83,6 +90,39 @@ const ADAPTERS_INFO: { }, } +/** + * Adds the /inertia route to the routes file + */ +async function defineExampleRoute(command: Configure, codemods: Codemods) { + const tsMorph = await codemods.getTsMorphProject() + const routesFile = tsMorph?.getSourceFile(command.app.makePath('./start/routes.ts')) + + if (!routesFile) { + return command.logger.warning('Unable to find the routes file') + } + + const isAlreadyDefined = routesFile.getText().includes('/inertia') + if (isAlreadyDefined) { + command.logger.warning('/inertia route is already defined. Skipping') + return + } + + const action = command.logger.action('update start/routes.ts file') + try { + routesFile?.addStatements((writer) => { + writer.writeLine( + `router.get('/inertia', ({ inertia }) => inertia.render('home', { version: 6 }))` + ) + }) + + await tsMorph?.save() + action.succeeded() + } catch (error) { + codemods.emit('error', error) + action.failed(error.message) + } +} + /** * Configures the package */ @@ -116,13 +156,16 @@ export async function configure(command: Configure) { /** * Publish stubs */ - const extension = adapterInfo.extension + const appExt = adapterInfo.appExtension const stubFolder = adapterInfo.stubFolder + const compExt = adapterInfo.componentsExtension await codemods.makeUsingStub(stubsRoot, 'config.stub', {}) + await codemods.makeUsingStub(stubsRoot, `app.css.stub`, {}) await codemods.makeUsingStub(stubsRoot, `${stubFolder}/root.edge.stub`, {}) await codemods.makeUsingStub(stubsRoot, `${stubFolder}/tsconfig.json.stub`, {}) - await codemods.makeUsingStub(stubsRoot, `${stubFolder}/app.${extension}.stub`, {}) + await codemods.makeUsingStub(stubsRoot, `${stubFolder}/app.${appExt}.stub`, {}) + await codemods.makeUsingStub(stubsRoot, `${stubFolder}/home.${compExt}.stub`, {}) /** * Update vite config @@ -132,6 +175,11 @@ export async function configure(command: Configure) { adapterInfo.viteRegister.importDeclarations ) + /** + * Add route example + */ + defineExampleRoute(command, codemods) + /** * Install packages */ @@ -147,7 +195,5 @@ export async function configure(command: Configure) { await codemods.listPackagesToInstall(pkgToInstall) } - command.logger.success( - 'Inertia was configured successfully. Please note that you still need to update your vite config, setup your Edge root view and others things. Read the docs for more info.' - ) + command.logger.success('Inertia configured') } diff --git a/stubs/app.css.stub b/stubs/app.css.stub new file mode 100644 index 0000000..840a018 --- /dev/null +++ b/stubs/app.css.stub @@ -0,0 +1,39 @@ +{{{ + exports({ to: app.makePath('resources/css/app.css') }) +}}} +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap'); + +* { + margin: 0; + padding: 0; +} + +html, +body, +#app { + background-color: #F7F8FA; + font-family: 'Poppins', sans-serif; + color: #46444c; + height: 100%; + width: 100%; +} + +.title { + font-size: 42px; + font-weight: 500; + color: #5a45ff; +} + +.container { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + height: 100%; + width: 100%; +} + +a { + text-decoration: underline; + color: #5a45ff; +} diff --git a/stubs/react/app.tsx.stub b/stubs/react/app.tsx.stub index fc66742..202f9d8 100644 --- a/stubs/react/app.tsx.stub +++ b/stubs/react/app.tsx.stub @@ -14,8 +14,8 @@ createInertiaApp({ title: (title) => {{ '`${title} - ${appName}`' }}, resolve: (name) => { - const pages = import.meta.glob('./pages/**/*.vue', { eager: true }) - {{ 'return pages[`./pages/${name}.vue`]' }} + const pages = import.meta.glob('./pages/**/*.tsx', { eager: true }) + {{ 'return pages[`./pages/${name}.tsx`]' }} }, setup({ el, App, props }) { diff --git a/stubs/react/home.tsx.stub b/stubs/react/home.tsx.stub new file mode 100644 index 0000000..ef8b8cf --- /dev/null +++ b/stubs/react/home.tsx.stub @@ -0,0 +1,21 @@ +{{{ + exports({ to: app.makePath('resources/pages/home.tsx') }) +}}} +import { Head } from '@inertiajs/react' + +export default function Home(props: { version: number }) { + return ( + <> + + +
+
AdonisJS {props.version} x Inertia x React
+ + + Learn more about AdonisJS and Inertia.js by visiting the{' '} + AdonisJS documentation. + +
+ + ) +} diff --git a/stubs/solid/home.tsx.stub b/stubs/solid/home.tsx.stub new file mode 100644 index 0000000..e400a97 --- /dev/null +++ b/stubs/solid/home.tsx.stub @@ -0,0 +1,21 @@ +{{{ + exports({ to: app.makePath('resources/pages/home.tsx') }) +}}} +import { Title } from '@solidjs/meta' + +export default function Home(props: { version: number }) { + return ( + <> + Homepage + +
+
AdonisJS {props.version} x Inertia x Solid.js
+ + + Learn more about AdonisJS and Inertia.js by visiting the{' '} + AdonisJS documentation. + +
+ + ) +} diff --git a/stubs/vue/home.vue.stub b/stubs/vue/home.vue.stub new file mode 100644 index 0000000..3866db1 --- /dev/null +++ b/stubs/vue/home.vue.stub @@ -0,0 +1,21 @@ +{{{ + exports({ to: app.makePath('resources/pages/home.vue') }) +}}} + + + diff --git a/tests/configure.spec.ts b/tests/configure.spec.ts index e428cea..1b4bb5c 100644 --- a/tests/configure.spec.ts +++ b/tests/configure.spec.ts @@ -14,6 +14,7 @@ import { BASE_URL } from '../tests_helpers/index.js' import { FileSystem } from '@japa/file-system' async function setupApp() { + console.log(BASE_URL) const ignitor = new IgnitorFactory() .withCoreProviders() .withCoreConfig() @@ -31,7 +32,7 @@ async function setupApp() { await app.init().then(() => app.boot()) const ace = await app.container.make('ace') - ace.ui.switchMode('raw') + // ace.ui.switchMode('raw') return { ace, app } } @@ -77,6 +78,40 @@ test.group('Configure', (group) => { await assert.fileContains('adonisrc.ts', '@adonisjs/inertia/inertia_provider') await assert.fileContains('start/kernel.ts', '@adonisjs/inertia/inertia_middleware') }) + + test('add example route', async ({ assert, fs }) => { + await fs.createJson('tsconfig.json', { compilerOptions: {} }) + await fs.create('start/routes.ts', '') + + const { ace } = await setupApp() + + ace.prompt.trap('adapter').replyWith('Vue 3') + ace.prompt.trap('install').reject() + + const command = await ace.create(Configure, ['../../index.js']) + await command.exec() + + await assert.fileContains('start/routes.ts', `router.get('/inertia'`) + }) + + test('skip adding example route when already defined', async ({ assert, fs }) => { + await fs.createJson('tsconfig.json', { compilerOptions: {} }) + await fs.create('start/routes.ts', `router.get('/inertia', () => {})`) + + const { ace } = await setupApp() + + ace.prompt.trap('adapter').replyWith('Vue 3') + ace.prompt.trap('install').reject() + + const command = await ace.create(Configure, ['../../index.js']) + await command.exec() + + const fileContent = await fs.contents('start/routes.ts') + const matches = fileContent.match(/router.get\('\/inertia'/g) + + assert.isArray(matches) + assert.lengthOf(matches!, 1) + }) }) test.group('Frameworks', (group) => { @@ -99,6 +134,7 @@ test.group('Frameworks', (group) => { await assert.fileExists('resources/views/root.edge') await assert.fileExists('resources/tsconfig.json') await assert.fileContains('vite.config.ts', '@vitejs/plugin-vue') + await assert.fileExists('resources/pages/home.vue') }) test('React', async ({ assert }) => { @@ -114,6 +150,7 @@ test.group('Frameworks', (group) => { await assert.fileExists('resources/views/root.edge') await assert.fileExists('resources/tsconfig.json') await assert.fileContains('vite.config.ts', '@vitejs/plugin-react') + await assert.fileExists('resources/pages/home.tsx') }) test('Solid', async ({ assert }) => { @@ -129,5 +166,6 @@ test.group('Frameworks', (group) => { await assert.fileExists('resources/views/root.edge') await assert.fileExists('resources/tsconfig.json') await assert.fileContains('vite.config.ts', 'vite-plugin-solid') + await assert.fileExists('resources/pages/home.tsx') }) }) From 692fb9cdfd028800f0e9175e88a56a97ea8fc542 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Sun, 18 Feb 2024 11:06:45 +0100 Subject: [PATCH 3/8] fix: vite plugin registration --- configure.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ts b/configure.ts index e1f571f..9aeaf46 100644 --- a/configure.ts +++ b/configure.ts @@ -37,7 +37,7 @@ const ADAPTERS_INFO: { ], viteRegister: { pluginCall: 'vue()', - importDeclarations: [{ isNamed: true, module: '@vitejs/plugin-vue', identifier: 'vue' }], + importDeclarations: [{ isNamed: false, module: '@vitejs/plugin-vue', identifier: 'vue' }], }, }, 'React': { @@ -54,7 +54,7 @@ const ADAPTERS_INFO: { ], viteRegister: { pluginCall: 'react()', - importDeclarations: [{ isNamed: true, module: '@vitejs/plugin-react', identifier: 'react' }], + importDeclarations: [{ isNamed: false, module: '@vitejs/plugin-react', identifier: 'react' }], }, }, 'Svelte': { @@ -69,7 +69,7 @@ const ADAPTERS_INFO: { viteRegister: { pluginCall: 'svelte()', importDeclarations: [ - { isNamed: true, module: '@sveltejs/vite-plugin-svelte', identifier: 'svelte' }, + { isNamed: false, module: '@sveltejs/vite-plugin-svelte', identifier: 'svelte' }, ], }, }, @@ -85,7 +85,7 @@ const ADAPTERS_INFO: { ], viteRegister: { pluginCall: 'solid()', - importDeclarations: [{ isNamed: true, module: 'vite-plugin-solid', identifier: 'solid' }], + importDeclarations: [{ isNamed: false, module: 'vite-plugin-solid', identifier: 'solid' }], }, }, } From bfd4aa9ac80e59a669e0b577d2d3a6f471dc25c8 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Sun, 18 Feb 2024 11:06:54 +0100 Subject: [PATCH 4/8] fix: className to class solid stub --- stubs/solid/home.tsx.stub | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stubs/solid/home.tsx.stub b/stubs/solid/home.tsx.stub index e400a97..d1a0e59 100644 --- a/stubs/solid/home.tsx.stub +++ b/stubs/solid/home.tsx.stub @@ -8,8 +8,8 @@ export default function Home(props: { version: number }) { <> Homepage -
-
AdonisJS {props.version} x Inertia x Solid.js
+
+
AdonisJS {props.version} x Inertia x Solid.js
Learn more about AdonisJS and Inertia.js by visiting the{' '} From 8106869d4cc08ce75f2aa849fc930ef0b85bd573 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Mon, 26 Feb 2024 14:44:13 +0100 Subject: [PATCH 5/8] feat: ssr version --- factories/inertia_factory.ts | 11 ++++- package.json | 37 +++++++------- providers/inertia_provider.ts | 5 +- src/define_config.ts | 6 +++ src/inertia.ts | 43 ++++++++++++++++- src/inertia_middleware.ts | 12 ++++- src/plugins/vite.ts | 66 +++++++++++++++++++++++++ src/types.ts | 31 ++++++++++++ tests/configure.spec.ts | 1 - tests/inertia.spec.ts | 82 ++++++++++++++++++++++++++++++++ tests/middleware.spec.ts | 7 +++ tests/plugins/api_client.spec.ts | 3 ++ tests/provider.spec.ts | 14 +++++- 13 files changed, 293 insertions(+), 25 deletions(-) create mode 100644 src/plugins/vite.ts diff --git a/factories/inertia_factory.ts b/factories/inertia_factory.ts index 99d35a0..0f8d3a1 100644 --- a/factories/inertia_factory.ts +++ b/factories/inertia_factory.ts @@ -7,10 +7,11 @@ * file that was distributed with this source code. */ +import type { ViteRuntime } from 'vite/runtime' import { HttpContext } from '@adonisjs/core/http' import { AppFactory } from '@adonisjs/core/factories/app' -import { HttpContextFactory } from '@adonisjs/core/factories/http' import { ApplicationService } from '@adonisjs/core/types' +import { HttpContextFactory } from '@adonisjs/core/factories/http' import { defineConfig } from '../index.js' import { Inertia } from '../src/inertia.js' @@ -29,6 +30,7 @@ export class InertiaFactory { #parameters: FactoryParameters = { ctx: new HttpContextFactory().create(), } + #viteRuntime?: ViteRuntime #getApp() { return new AppFactory().create(new URL('./', import.meta.url), () => {}) as ApplicationService @@ -50,6 +52,11 @@ export class InertiaFactory { return this } + withViteRuntime(runtime: { executeEntrypoint: (path: string) => Promise }) { + this.#viteRuntime = runtime as any + return this + } + withInertiaPartialData(data: string[]) { this.#parameters.ctx.request.request.headers['x-inertia-partial-data'] = data.join(',') return this @@ -62,6 +69,6 @@ export class InertiaFactory { async create() { const config = await defineConfig(this.#parameters.config || {}).resolver(this.#getApp()) - return new Inertia(this.#parameters.ctx, config) + return new Inertia(this.#parameters.ctx, config, this.#viteRuntime) } } diff --git a/package.json b/package.json index 213807e..d9c7832 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "./inertia_middleware": "./build/src/inertia_middleware.js", "./inertia_provider": "./build/providers/inertia_provider.js", "./plugins/edge": "./build/src/plugins/edge/plugin.js", - "./plugins/api_client": "./build/src/plugins/api_client.js" + "./plugins/api_client": "./build/src/plugins/japa/api_client.js", + "./client": "./build/src/plugins/vite.js" }, "scripts": { "clean": "del-cli build", @@ -36,39 +37,42 @@ "prepublishOnly": "npm run build" }, "devDependencies": { - "@adonisjs/assembler": "^7.0.0", - "@adonisjs/core": "6.2.0", + "@adonisjs/assembler": "^7.2.1", + "@adonisjs/core": "6.3.0", "@adonisjs/eslint-config": "^1.2.1", "@adonisjs/prettier-config": "^1.2.1", - "@adonisjs/session": "7.0.0", + "@adonisjs/session": "7.1.1", "@adonisjs/tsconfig": "^1.2.1", + "@adonisjs/vite": "^3.0.0-0", "@japa/api-client": "^2.0.2", "@japa/assert": "2.1.0", "@japa/expect-type": "^2.0.1", - "@japa/file-system": "^2.1.1", - "@japa/plugin-adonisjs": "^2.0.2", + "@japa/file-system": "^2.2.0", + "@japa/plugin-adonisjs": "^2.0.3", "@japa/runner": "3.1.1", - "@swc/core": "^1.3.102", - "@types/node": "^20.10.8", + "@swc/core": "^1.4.2", + "@types/node": "^20.11.20", "@types/qs": "^6.9.11", "@types/supertest": "^6.0.2", - "c8": "^9.0.0", + "@vavite/multibuild": "^4.1.1", + "c8": "^9.1.0", "copyfiles": "^2.4.1", "del-cli": "^5.1.0", "edge-parser": "^9.0.1", "edge.js": "^6.0.1", - "eslint": "^8.56.0", + "eslint": "^8.57.0", "get-port": "^7.0.0", "np": "^9.2.0", - "prettier": "^3.1.1", - "supertest": "^6.3.3", - "tinybench": "^2.5.1", + "prettier": "^3.2.5", + "supertest": "^6.3.4", + "tinybench": "^2.6.0", "ts-node": "^10.9.2", - "tsup": "^8.0.1", - "typescript": "~5.3.3" + "tsup": "^8.0.2", + "typescript": "~5.3.3", + "vite": "^5.1.4" }, "dependencies": { - "@poppinss/utils": "^6.7.0", + "@poppinss/utils": "^6.7.2", "crc-32": "^1.2.2", "edge-error": "^4.0.1", "html-entities": "^2.4.0", @@ -77,6 +81,7 @@ "peerDependencies": { "@adonisjs/core": "^6.2.0", "@adonisjs/session": "^7.0.0", + "@adonisjs/vite": "^2.0.2", "@japa/api-client": "^2.0.0", "edge.js": "^6.0.0" }, diff --git a/providers/inertia_provider.ts b/providers/inertia_provider.ts index 7041f7e..cc1d38d 100644 --- a/providers/inertia_provider.ts +++ b/providers/inertia_provider.ts @@ -7,6 +7,8 @@ * file that was distributed with this source code. */ +/// + import { configProvider } from '@adonisjs/core' import { RuntimeException } from '@poppinss/utils' import type { ApplicationService } from '@adonisjs/core/types' @@ -38,6 +40,7 @@ export default class InertiaProvider { this.app.container.singleton(InertiaMiddleware, async () => { const inertiaConfigProvider = this.app.config.get('inertia') const config = await configProvider.resolve(this.app, inertiaConfigProvider) + const vite = await this.app.container.make('vite') if (!config) { throw new RuntimeException( @@ -45,7 +48,7 @@ export default class InertiaProvider { ) } - return new InertiaMiddleware(config) + return new InertiaMiddleware(config, vite) }) await this.registerEdgePlugin() diff --git a/src/define_config.ts b/src/define_config.ts index 890e150..0a456bf 100644 --- a/src/define_config.ts +++ b/src/define_config.ts @@ -25,6 +25,12 @@ export function defineConfig(config: InertiaConfig): ConfigProvider +import type { Vite } from '@adonisjs/vite' import type { HttpContext } from '@adonisjs/core/http' + import type { Data, MaybePromise, PageProps, ResolvedConfig, SharedData } from './types.js' /** @@ -25,7 +27,8 @@ export class Inertia { constructor( protected ctx: HttpContext, - protected config: ResolvedConfig + protected config: ResolvedConfig, + protected viteRuntime?: ReturnType ) { this.#sharedData = config.sharedData } @@ -97,6 +100,41 @@ export class Inertia { } } + /** + * If the page should be rendered on the server + */ + #shouldRenderOnServer(component: string) { + const isSsrEnabled = this.config.ssr.enabled + const isSsrEnabledForPage = this.config.ssr.pages + ? this.config.ssr.pages.includes(component) + : true + + return isSsrEnabled && isSsrEnabledForPage + } + + /** + * Render the page on the server + * + * On development, we use the Vite Runtime API + * On production, we just import and use the SSR bundle generated by Vite + */ + async #renderOnServer(pageObject: any, viewProps?: Record) { + let render: { default: (page: any) => Promise<{ head: string; body: string }> } + + if (this.viteRuntime) { + render = await this.viteRuntime.executeEntrypoint(this.config.ssr.entrypoint!) + } else { + render = await import(this.config.ssr.bundle!) + } + + const result = await render.default(pageObject) + + return this.ctx.view.render(this.config.rootView, { + ...viewProps, + page: { ssrHead: result.head, ssrBody: result.body }, + }) + } + /** * Share data for the current request. * This data will override any shared data defined in the config. @@ -116,6 +154,9 @@ export class Inertia { const isInertiaRequest = !!this.ctx.request.header('x-inertia') if (!isInertiaRequest) { + const shouldRenderOnServer = this.#shouldRenderOnServer(component) + if (shouldRenderOnServer) return this.#renderOnServer(pageObject, viewProps) + return this.ctx.view.render(this.config.rootView, { ...viewProps, page: pageObject }) } diff --git a/src/inertia_middleware.ts b/src/inertia_middleware.ts index f9b5fe9..7ec2249 100644 --- a/src/inertia_middleware.ts +++ b/src/inertia_middleware.ts @@ -7,6 +7,7 @@ * file that was distributed with this source code. */ +import type { Vite } from '@adonisjs/vite' import type { HttpContext } from '@adonisjs/core/http' import type { NextFn } from '@adonisjs/core/types/http' @@ -27,12 +28,19 @@ declare module '@adonisjs/core/http' { * set appropriate headers/status */ export default class InertiaMiddleware { - constructor(protected config: ResolvedConfig) {} + #runtime: ReturnType | undefined + + constructor( + protected config: ResolvedConfig, + vite?: Vite + ) { + this.#runtime = vite?.getRuntime() + } async handle(ctx: HttpContext, next: NextFn) { const { response, request } = ctx - ctx.inertia = new Inertia(ctx, this.config) + ctx.inertia = new Inertia(ctx, this.config, this.#runtime) await next() diff --git a/src/plugins/vite.ts b/src/plugins/vite.ts new file mode 100644 index 0000000..f35e6f5 --- /dev/null +++ b/src/plugins/vite.ts @@ -0,0 +1,66 @@ +/* + * @adonisjs/inertia + * + * (c) AdonisJS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/// + +import type { PluginOption } from 'vite' + +export type InertiaPluginOptions = { + ssr?: + | { + /** + * Whether or not to enable server-side rendering + */ + enabled: true + + /** + * The entrypoint for the server-side rendering + */ + entrypoint: string + + /** + * The output directory for the server-side rendering bundle + */ + output?: string + } + | { enabled: false } +} + +/** + * Inertia plugin for Vite that is tailored for AdonisJS + */ +export default function inertia(options: InertiaPluginOptions): PluginOption { + return { + name: 'vite-plugin-inertia', + config: () => { + if (!options.ssr?.enabled) return {} + + return { + buildSteps: [ + { + name: 'build-client', + description: 'build inertia client bundle', + config: { build: { outDir: 'build/public/assets/' } }, + }, + { + name: 'build-ssr', + description: 'build inertia server bundle', + config: { + build: { + ssr: true, + outDir: options.ssr.output || 'build/ssr', + rollupOptions: { input: options.ssr.entrypoint }, + }, + }, + }, + ], + } + }, + } +} diff --git a/src/types.ts b/src/types.ts index a8f1e0c..760004e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -46,6 +46,31 @@ export interface InertiaConfig { * Data that should be shared with all rendered pages */ sharedData?: SharedData + + /** + * Options to configure SSR + */ + ssr?: { + /** + * Enable or disable SSR + */ + enabled: boolean + + /** + * List of components that should be rendered on the server + */ + pages?: string[] + + /** + * Path to the SSR entrypoint file + */ + entrypoint?: string + + /** + * Path to the SSR bundled file that will be used in production + */ + bundle?: string + } } /** @@ -55,4 +80,10 @@ export interface ResolvedConfig { rootView: string versionCache: VersionCache sharedData: SharedData + ssr: { + enabled: boolean + entrypoint: string + pages?: string[] + bundle: string + } } diff --git a/tests/configure.spec.ts b/tests/configure.spec.ts index 1b4bb5c..915c163 100644 --- a/tests/configure.spec.ts +++ b/tests/configure.spec.ts @@ -14,7 +14,6 @@ import { BASE_URL } from '../tests_helpers/index.js' import { FileSystem } from '@japa/file-system' async function setupApp() { - console.log(BASE_URL) const ignitor = new IgnitorFactory() .withCoreProviders() .withCoreConfig() diff --git a/tests/inertia.spec.ts b/tests/inertia.spec.ts index c865664..7c04ed2 100644 --- a/tests/inertia.spec.ts +++ b/tests/inertia.spec.ts @@ -7,6 +7,7 @@ * file that was distributed with this source code. */ +import { join } from 'node:path' import { test } from '@japa/runner' import { HttpContext } from '@adonisjs/core/http' import { HttpContextFactory, RequestFactory } from '@adonisjs/core/factories/http' @@ -255,3 +256,84 @@ test.group('Inertia', () => { assert.deepEqual(result.props, { foo: 'baz' }) }) }) + +test.group('Inertia | Ssr', () => { + test('if viteRuntime is available, use entrypoint file to render the page', async ({ + assert, + }) => { + setupViewMacroMock() + + const inertia = await new InertiaFactory() + .merge({ + config: { + ssr: { + enabled: true, + entrypoint: 'foo.ts', + }, + }, + }) + .withViteRuntime({ + async executeEntrypoint(path) { + return { default: () => ({ head: 'head', body: path }) } + }, + }) + .create() + + const result: any = await inertia.render('foo') + + assert.deepEqual(result.props.page.ssrHead, 'head') + assert.deepEqual(result.props.page.ssrBody, 'foo.ts') + }) + + test('if viteRuntime is not available, use bundle file to render the page', async ({ + assert, + fs, + }) => { + setupViewMacroMock() + + await fs.create('foo.js', 'export default () => ({ head: "head", body: "foo.ts" })') + + const inertia = await new InertiaFactory() + .merge({ + config: { + ssr: { + enabled: true, + bundle: join(fs.basePath, 'foo.js'), + }, + }, + }) + .create() + + const result: any = await inertia.render('foo') + + assert.deepEqual(result.props.page.ssrBody, 'foo.ts') + assert.deepEqual(result.props.page.ssrHead, 'head') + }) + + test('enable only for listed pages', async ({ assert }) => { + setupViewMacroMock() + + const inertia = await new InertiaFactory() + .withViteRuntime({ + async executeEntrypoint(path) { + return { default: () => ({ head: 'head', body: path }) } + }, + }) + .merge({ + config: { + ssr: { + enabled: true, + entrypoint: 'foo.ts', + pages: ['foo'], + }, + }, + }) + .create() + + const result: any = await inertia.render('foo') + const result2: any = await inertia.render('bar') + + assert.deepEqual(result.props.page.ssrBody, 'foo.ts') + assert.notExists(result2.props.page.ssrBody) + }) +}) diff --git a/tests/middleware.spec.ts b/tests/middleware.spec.ts index 6939026..e54b385 100644 --- a/tests/middleware.spec.ts +++ b/tests/middleware.spec.ts @@ -25,6 +25,7 @@ test.group('Middleware', () => { rootView: 'root', sharedData: {}, versionCache: new VersionCache(new URL(import.meta.url), '1'), + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) await middleware.handle(ctx, () => {}) @@ -46,6 +47,7 @@ test.group('Middleware', () => { rootView: 'root', sharedData: {}, versionCache: new VersionCache(new URL(import.meta.url), '1'), + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) await middleware.handle(ctx, () => { @@ -74,6 +76,7 @@ test.group('Middleware', () => { rootView: 'root', sharedData: {}, versionCache: new VersionCache(new URL(import.meta.url), '1'), + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) await middleware.handle(ctx, () => { @@ -102,6 +105,7 @@ test.group('Middleware', () => { rootView: 'root', sharedData: {}, versionCache: new VersionCache(new URL(import.meta.url), '1'), + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) await middleware.handle(ctx, () => { @@ -128,6 +132,7 @@ test.group('Middleware', () => { rootView: 'root', sharedData: {}, versionCache: new VersionCache(new URL(import.meta.url), '1'), + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) await middleware.handle(ctx, () => {}) @@ -148,6 +153,7 @@ test.group('Middleware', () => { rootView: 'root', sharedData: {}, versionCache: version, + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) const server = httpServer.create(async (req, res) => { @@ -178,6 +184,7 @@ test.group('Middleware', () => { rootView: 'root', sharedData: {}, versionCache: version, + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) const server = httpServer.create(async (req, res) => { diff --git a/tests/plugins/api_client.spec.ts b/tests/plugins/api_client.spec.ts index 3d4e06a..34e4f14 100644 --- a/tests/plugins/api_client.spec.ts +++ b/tests/plugins/api_client.spec.ts @@ -74,6 +74,7 @@ test.group('Japa plugin | Api Client', (group) => { versionCache: new VersionCache(new URL(import.meta.url), '1'), rootView: 'root', sharedData: {}, + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) await middleware.handle(ctx, async () => { @@ -114,6 +115,7 @@ test.group('Japa plugin | Api Client', (group) => { versionCache: new VersionCache(new URL(import.meta.url), '1'), rootView: 'root', sharedData: {}, + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) await middleware.handle(ctx, async () => { @@ -147,6 +149,7 @@ test.group('Japa plugin | Api Client', (group) => { versionCache: new VersionCache(new URL(import.meta.url), '1'), rootView: 'root', sharedData: {}, + ssr: { enabled: false, bundle: '', entrypoint: '' }, }) await middleware.handle(ctx, async () => { diff --git a/tests/provider.spec.ts b/tests/provider.spec.ts index 41d773a..affd3fd 100644 --- a/tests/provider.spec.ts +++ b/tests/provider.spec.ts @@ -2,6 +2,7 @@ import { test } from '@japa/runner' import { IgnitorFactory } from '@adonisjs/core/factories' import { defineConfig } from '../index.js' +import { defineConfig as viteDefineConfig } from '@adonisjs/vite' import InertiaMiddleware from '../src/inertia_middleware.js' const BASE_URL = new URL('./tmp/', import.meta.url) @@ -15,10 +16,19 @@ const IMPORTER = (filePath: string) => { test.group('Inertia Provider', () => { test('register inertia middleware singleton', async ({ assert }) => { const ignitor = new IgnitorFactory() - .merge({ rcFileContents: { providers: [() => import('../providers/inertia_provider.js')] } }) + .merge({ + rcFileContents: { + providers: [ + () => import('../providers/inertia_provider.js'), + () => import('@adonisjs/vite/vite_provider'), + ], + }, + }) .withCoreConfig() .withCoreProviders() - .merge({ config: { inertia: defineConfig({ rootView: 'root' }) } }) + .merge({ + config: { inertia: defineConfig({ rootView: 'root' }), vite: viteDefineConfig({}) }, + }) .create(BASE_URL, { importer: IMPORTER }) const app = ignitor.createApp('web') From 4bfa15645a39c99ac0024307f0ec7143f8351055 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Mon, 26 Feb 2024 14:48:22 +0100 Subject: [PATCH 6/8] fix: test --- tests/inertia.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/inertia.spec.ts b/tests/inertia.spec.ts index 7c04ed2..ecb8ac9 100644 --- a/tests/inertia.spec.ts +++ b/tests/inertia.spec.ts @@ -7,8 +7,8 @@ * file that was distributed with this source code. */ -import { join } from 'node:path' import { test } from '@japa/runner' +import { fileURLToPath } from 'node:url' import { HttpContext } from '@adonisjs/core/http' import { HttpContextFactory, RequestFactory } from '@adonisjs/core/factories/http' @@ -298,7 +298,7 @@ test.group('Inertia | Ssr', () => { config: { ssr: { enabled: true, - bundle: join(fs.basePath, 'foo.js'), + bundle: fileURLToPath(new URL('foo.js', fs.baseUrl)), }, }, }) From 6bde17a82cdddffc1cda27537cb96c40a341283b Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Mon, 26 Feb 2024 14:54:48 +0100 Subject: [PATCH 7/8] fix: windows test --- tests/inertia.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/inertia.spec.ts b/tests/inertia.spec.ts index ecb8ac9..c0d6756 100644 --- a/tests/inertia.spec.ts +++ b/tests/inertia.spec.ts @@ -298,7 +298,7 @@ test.group('Inertia | Ssr', () => { config: { ssr: { enabled: true, - bundle: fileURLToPath(new URL('foo.js', fs.baseUrl)), + bundle: new URL('foo.js', fs.baseUrl).href, }, }, }) From 49c51e4929611380bb777effba310c27246fe503 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Mon, 26 Feb 2024 14:56:45 +0100 Subject: [PATCH 8/8] chore: remove unused variable --- tests/inertia.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/inertia.spec.ts b/tests/inertia.spec.ts index c0d6756..0f74b5f 100644 --- a/tests/inertia.spec.ts +++ b/tests/inertia.spec.ts @@ -8,7 +8,6 @@ */ import { test } from '@japa/runner' -import { fileURLToPath } from 'node:url' import { HttpContext } from '@adonisjs/core/http' import { HttpContextFactory, RequestFactory } from '@adonisjs/core/factories/http'