Skip to content

Commit

Permalink
feat: support ssr: false (#351)
Browse files Browse the repository at this point in the history
Co-Authored-By: Daniel Roe <daniel@roe.dev>
  • Loading branch information
pi0 and danielroe authored Jul 21, 2021
1 parent e7b1d52 commit ddc045e
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 20 deletions.
4 changes: 3 additions & 1 deletion src/compat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ export default function nuxt2CompatModule () {
// Disable server sourceMap, esbuild will generate for it.
nuxt.hook('webpack:config', (webpackConfigs) => {
const serverConfig = webpackConfigs.find(config => config.name === 'server')
serverConfig.devtool = false
if (serverConfig) {
serverConfig.devtool = false
}
})

// Nitro client plugin
Expand Down
2 changes: 2 additions & 0 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface NitroContext {
_nuxt: {
majorVersion: number
dev: boolean
ssr: boolean
rootDir: string
srcDir: string
buildDir: string
Expand Down Expand Up @@ -99,6 +100,7 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
_nuxt: {
majorVersion: nuxtOptions._majorVersion || 2,
dev: nuxtOptions.dev,
ssr: nuxtOptions.ssr,
rootDir: nuxtOptions.rootDir,
srcDir: nuxtOptions.srcDir,
buildDir: nuxtOptions.buildDir,
Expand Down
14 changes: 14 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
declare module '#build/dist/server/client.manifest.mjs' {
type ClientManifest = any // TODO: export from vue-bundle-renderer
const clientManifest: ClientManifest
export default clientManifest
}

declare module '#build/dist/server/server.mjs' {
const _default: any
export default _default
}

declare module '#nitro-renderer' {
export const renderToString: Function
}
2 changes: 1 addition & 1 deletion src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"unstorage": "^0.2.3",
"upath": "^2.0.1",
"vue": "3.1.5",
"vue-bundle-renderer": "^0.2.5",
"vue-bundle-renderer": "^0.2.9",
"vue-server-renderer": "^2.6.14"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions src/rollup/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export const getRollupConfig = (nitroContext: NitroContext) => {
'global.': 'globalThis.',
'process.server': 'true',
'process.client': 'false',
'process.env.NUXT_NO_SSR': JSON.stringify(!nitroContext._nuxt.ssr),
'process.env.ROUTER_BASE': JSON.stringify(nitroContext._nuxt.routerBase),
'process.env.PUBLIC_PATH': JSON.stringify(nitroContext._nuxt.publicPath),
'process.env.NUXT_STATIC_BASE': JSON.stringify(nitroContext._nuxt.staticAssets.base),
Expand Down
80 changes: 62 additions & 18 deletions src/runtime/app/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,47 @@ import { runtimeConfig } from './config'
// @ts-ignore
import htmlTemplate from '#build/views/document.template.mjs'

function _interopDefault (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e }

const STATIC_ASSETS_BASE = process.env.NUXT_STATIC_BASE + '/' + process.env.NUXT_STATIC_VERSION
const NUXT_NO_SSR = process.env.NUXT_NO_SSR
const PAYLOAD_JS = '/payload.js'

let _renderer
async function loadRenderer () {
if (_renderer) {
return _renderer
}
// @ts-ignore
const getClientManifest = cachedImport(() => import('#build/dist/server/client.manifest.mjs'))
const getSSRApp = cachedImport(() => import('#build/dist/server/server.mjs'))

const getSSRRenderer = cachedResult(async () => {
// Load client manifest
const clientManifest = await getClientManifest()
if (!clientManifest) { throw new Error('client.manifest is missing') }
// Load server bundle
const createSSRApp = await getSSRApp()
if (!createSSRApp) { throw new Error('Server bundle is missing') }
// Create renderer
const { renderToString } = await import('#nitro-renderer')
// @ts-ignore
const createApp = await import('#build/dist/server/server.mjs')
// @ts-ignore
const clientManifest = await import('#build/dist/server/client.manifest.mjs')
_renderer = createRenderer(_interopDefault(createApp), {
clientManifest: _interopDefault(clientManifest),
renderToString
return createRenderer((createSSRApp), { clientManifest, renderToString }).renderToString
})

const getSPARenderer = cachedResult(async () => {
const clientManifest = await getClientManifest()
return (ssrContext) => {
ssrContext.nuxt = {}
return {
html: '<div id="__nuxt"></div>',
renderResourceHints: () => '',
renderStyles: () => '',
renderScripts: () => clientManifest.initial.map((s) => {
const isMJS = !s.endsWith('.js')
return `<script ${isMJS ? 'type="module"' : ''} src="${clientManifest.publicPath}${s}"></script>`
}).join('')
}
}
})

function renderToString (ssrContext) {
const getRenderer = (NUXT_NO_SSR || ssrContext.noSSR) ? getSPARenderer : getSSRRenderer
return getRenderer().then(renderToString => renderToString(ssrContext)).catch((err) => {
console.warn('Server Side Rendering Error:', err)
return getSPARenderer().then(renderToString => renderToString(ssrContext))
})
return _renderer
}

export async function renderMiddleware (req, res) {
Expand All @@ -37,15 +57,18 @@ export async function renderMiddleware (req, res) {
url = url.substr(STATIC_ASSETS_BASE.length, url.length - STATIC_ASSETS_BASE.length - PAYLOAD_JS.length)
}

// Initialize ssr context
const ssrContext = {
url,
req,
res,
runtimeConfig,
noSSR: req.spa || req.headers['x-nuxt-no-ssr'],
...(req.context || {})
}
const renderer = await loadRenderer()
const rendered = await renderer.renderToString(ssrContext)

// Render app
const rendered = await renderToString(ssrContext)

// Handle errors
if (ssrContext.error) {
Expand Down Expand Up @@ -107,3 +130,24 @@ async function renderHTML (payload, rendered, ssrContext) {
function renderPayload (payload, url) {
return `__NUXT_JSONP__("${url}", ${devalue(payload)})`
}

function _interopDefault (e) {
return e && typeof e === 'object' && 'default' in e ? e.default : e
}

function cachedImport <M> (importer: () => Promise<M>) {
return cachedResult(() => importer().then(_interopDefault).catch((err) => {
if (err.code === 'ERR_MODULE_NOT_FOUND') { return null }
throw err
}))
}

function cachedResult <T> (fn: () => Promise<T>): () => Promise<T> {
let res = null
return () => {
if (res === null) {
res = fn().catch((err) => { res = null; throw err })
}
return res
}
}
5 changes: 5 additions & 0 deletions src/server/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ export function createDevServer (nitroContext: NitroContext) {
const proxy = createProxy()
app.use((req, res) => {
if (workerAddress) {
// Workaround to pass legacy req.spa to proxy
// @ts-ignore
if (req.spa) {
req.headers['x-nuxt-no-ssr'] = 'true'
}
proxy.web(req, res, { target: workerAddress }, (_err: unknown) => {
// console.error('[proxy]', err)
})
Expand Down

0 comments on commit ddc045e

Please sign in to comment.