Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: SSR ready version #3

Merged
merged 8 commits into from
Feb 26, 2024
Merged
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
3 changes: 2 additions & 1 deletion bin/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

/*
|--------------------------------------------------------------------------
Expand All @@ -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()],
})

/*
Expand Down
134 changes: 109 additions & 25 deletions configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,42 @@
*/

import type Configure from '@adonisjs/core/commands/configure'
import { Codemods } from '@adonisjs/core/ace/codemods'

import { stubsRoot } from './stubs/main.js'

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
appExtension: string
componentsExtension: string
dependencies: { name: string; isDevDependency: boolean }[]
ssrDependencies?: { name: string; isDevDependency: boolean }[]
viteRegister: {
pluginCall: Parameters<Codemods['registerVitePlugin']>[0]
importDeclarations: Parameters<Codemods['registerVitePlugin']>[1]
}
}
} = {
'Vue 3': {
stubFolder: 'vue',
appExtension: 'ts',
componentsExtension: 'vue',
dependencies: [
{ name: '@inertiajs/vue3', isDevDependency: false },
{ name: 'vue', isDevDependency: false },
{ name: '@vitejs/plugin-vue', isDevDependency: true },
],
viteRegister: {
pluginCall: 'vue()',
importDeclarations: [{ isNamed: false, module: '@vitejs/plugin-vue', identifier: 'vue' }],
},
},
'React': {
stubFolder: 'react',
appExtension: 'tsx',
componentsExtension: 'tsx',
dependencies: [
{ name: '@inertiajs/react', isDevDependency: false },
{ name: 'react', isDevDependency: false },
Expand All @@ -39,16 +52,77 @@ const ADAPTERS_INFO: {
{ name: '@types/react', isDevDependency: true },
{ name: '@types/react-dom', isDevDependency: true },
],
viteRegister: {
pluginCall: 'react()',
importDeclarations: [{ isNamed: false, module: '@vitejs/plugin-react', identifier: 'react' }],
},
},
'Svelte': {
stubFolder: 'svelte',
appExtension: 'ts',
componentsExtension: 'svelte',
dependencies: [
{ name: '@inertiajs/svelte', isDevDependency: false },
{ name: 'svelte', isDevDependency: false },
{ name: '@sveltejs/vite-plugin-svelte', isDevDependency: true },
],
viteRegister: {
pluginCall: 'svelte()',
importDeclarations: [
{ isNamed: false, module: '@sveltejs/vite-plugin-svelte', identifier: 'svelte' },
],
},
},
'Solid': {
stubFolder: 'solid',
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()',
importDeclarations: [{ isNamed: false, module: 'vite-plugin-solid', identifier: 'solid' }],
},
},
}

/**
* 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
*/
Expand All @@ -61,19 +135,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()

/**
Expand All @@ -91,13 +154,36 @@ export async function configure(command: Configure) {
])

/**
* Publish config
* Publish stubs
*/
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.${appExt}.stub`, {})
await codemods.makeUsingStub(stubsRoot, `${stubFolder}/home.${compExt}.stub`, {})

/**
* Update vite config
*/
await codemods.registerVitePlugin(
adapterInfo.viteRegister.pluginCall,
adapterInfo.viteRegister.importDeclarations
)

/**
* Add route example
*/
defineExampleRoute(command, codemods)

/**
* 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' }
Expand All @@ -109,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')
}
11 changes: 9 additions & 2 deletions factories/inertia_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
Expand All @@ -50,6 +52,11 @@ export class InertiaFactory {
return this
}

withViteRuntime(runtime: { executeEntrypoint: (path: string) => Promise<any> }) {
this.#viteRuntime = runtime as any
return this
}

withInertiaPartialData(data: string[]) {
this.#parameters.ctx.request.request.headers['x-inertia-partial-data'] = data.join(',')
return this
Expand All @@ -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)
}
}
37 changes: 21 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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"
},
Expand Down
5 changes: 4 additions & 1 deletion providers/inertia_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* file that was distributed with this source code.
*/

/// <reference types="@adonisjs/vite/vite_provider" />

import { configProvider } from '@adonisjs/core'
import { RuntimeException } from '@poppinss/utils'
import type { ApplicationService } from '@adonisjs/core/types'
Expand Down Expand Up @@ -38,14 +40,15 @@ export default class InertiaProvider {
this.app.container.singleton(InertiaMiddleware, async () => {
const inertiaConfigProvider = this.app.config.get<InertiaConfig>('inertia')
const config = await configProvider.resolve<ResolvedConfig>(this.app, inertiaConfigProvider)
const vite = await this.app.container.make('vite')

if (!config) {
throw new RuntimeException(
'Invalid "config/inertia.ts" file. Make sure you are using the "defineConfig" method'
)
}

return new InertiaMiddleware(config)
return new InertiaMiddleware(config, vite)
})

await this.registerEdgePlugin()
Expand Down
6 changes: 6 additions & 0 deletions src/define_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ export function defineConfig(config: InertiaConfig): ConfigProvider<ResolvedConf
rootView: config.rootView ?? 'root',
sharedData: config.sharedData || {},
versionCache,
ssr: {
enabled: config.ssr?.enabled ?? false,
pages: config.ssr?.pages,
entrypoint: config.ssr?.entrypoint ?? app.makePath('resources/ssr.ts'),
bundle: config.ssr?.bundle ?? app.makePath('ssr/ssr.js'),
},
}
})
}
Loading
Loading