Skip to content

Commit

Permalink
fix(ssr): avoid transforming json file in ssrTransform (#6597)
Browse files Browse the repository at this point in the history
  • Loading branch information
poyoho authored May 10, 2022
1 parent 86b29e7 commit a709440
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 5 deletions.
23 changes: 23 additions & 0 deletions packages/playground/json/index.ssr.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div class="fetch-json-module">
json-module:
<pre></pre>
<code></code>
</div>
<div class="fetch-json-fs">
json-fs:
<pre></pre>
<code></code>
</div>

<script type="module">
const startModule = Date.now()
text('.fetch-json-module pre', await (await fetch('/json-module')).text())
text('.fetch-json-module code', Date.now() - startModule)

const startFs = Date.now()
text('.fetch-json-fs pre', await (await fetch('/json-fs')).text())
text('.fetch-json-fs code', Date.now() - startFs)
function text(sel, text) {
document.querySelector(sel).textContent = text
}
</script>
88 changes: 88 additions & 0 deletions packages/playground/json/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// @ts-check
const fs = require('fs')
const path = require('path')
const express = require('express')

const isTest = process.env.NODE_ENV === 'test' || !!process.env.VITE_TEST_BUILD

async function createServer(
root = process.cwd(),
isProd = process.env.NODE_ENV === 'production'
) {
const resolve = (p) => path.resolve(__dirname, p)
const app = express()

/**
* @type {import('vite').ViteDevServer}
*/
let vite
vite = await require('vite').createServer({
root,
logLevel: isTest ? 'error' : 'info',
server: {
middlewareMode: 'ssr',
watch: {
// During tests we edit the files too fast and sometimes chokidar
// misses change events, so enforce polling for consistency
usePolling: true,
interval: 100
}
},
json: {
stringify: true
}
})
// use vite's connect instance as middleware
app.use(vite.middlewares)

app.use('*', async (req, res) => {
try {
let [url] = req.originalUrl.split('?')
if (url.endsWith('/')) url += 'index.ssr.html'

if (url === '/json-module') {
console.time('load module')
const json = JSON.stringify(await vite.ssrLoadModule('/test.json'))
console.timeEnd('load module')
res.status(200).end('' + json.length)
return
}

if (url === '/json-fs') {
console.time('transform module')
const source = fs.readFileSync('./test.json', { encoding: 'utf-8' })
const json = await vite.ssrTransform(
`export default ${source}`,
null,
'./output.json'
)
console.timeEnd('transform module')
res.status(200).end(String(json.code.length))
return
}

const htmlLoc = resolve(`.${url}`)
let html = fs.readFileSync(htmlLoc, 'utf8')
html = await vite.transformIndexHtml(url, html)

res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
} catch (e) {
vite && vite.ssrFixStacktrace(e)
console.log(e.stack)
res.status(500).end(e.stack)
}
})

return { app, vite }
}

if (!isTest) {
createServer().then(({ app }) =>
app.listen(3000, () => {
console.log('http://localhost:3000')
})
)
}

// for test use
exports.createServer = createServer
7 changes: 6 additions & 1 deletion packages/vite/src/node/plugins/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
*/

import { dataToEsm } from '@rollup/pluginutils'
import type { Plugin } from 'rollup'
import { SPECIAL_QUERY_RE } from '../constants'
import type { Plugin } from '../plugin'

export interface JsonOptions {
/**
Expand All @@ -27,6 +27,11 @@ export interface JsonOptions {
// Custom json filter for vite
const jsonExtRE = /\.json($|\?)(?!commonjs-(proxy|external))/

const jsonLangs = `\\.(json|json5)($|\\?)`
const jsonLangRE = new RegExp(jsonLangs)
export const isJSONRequest = (request: string): boolean =>
jsonLangRE.test(request)

export function jsonPlugin(
options: JsonOptions = {},
isBuild: boolean
Expand Down
6 changes: 5 additions & 1 deletion packages/vite/src/node/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,11 @@ export async function createServer(
pluginContainer: container,
ws,
moduleGraph,
ssrTransform,
ssrTransform(code: string, inMap: SourceMap | null, url: string) {
return ssrTransform(code, inMap, url, {
json: { stringify: server.config.json?.stringify }
})
},
transformRequest(url, options) {
return transformRequest(url, server, options)
},
Expand Down
4 changes: 3 additions & 1 deletion packages/vite/src/node/server/transformRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,9 @@ async function doTransform(
}

const result = ssr
? await ssrTransform(code, map as SourceMap, url)
? await ssrTransform(code, map as SourceMap, url, {
json: { stringify: !!server.config.json?.stringify }
})
: ({
code,
map,
Expand Down
1 change: 0 additions & 1 deletion packages/vite/src/node/ssr/ssrModuleLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ async function instantiateModule(
if (mod.ssrModule) {
return mod.ssrModule
}

const result =
mod.ssrTransformResult ||
(await transformRequest(url, server, { ssr: true }))
Expand Down
31 changes: 31 additions & 0 deletions packages/vite/src/node/ssr/ssrTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,51 @@ import type {
import { extract_names as extractNames } from 'periscopic'
import { walk as eswalk } from 'estree-walker'
import { combineSourcemaps } from '../utils'
import { isJSONRequest } from '../plugins/json'
import type { RawSourceMap } from '@ampproject/remapping'

type Node = _Node & {
start: number
end: number
}

interface TransformOptions {
json?: {
stringify?: boolean
}
}

export const ssrModuleExportsKey = `__vite_ssr_exports__`
export const ssrImportKey = `__vite_ssr_import__`
export const ssrDynamicImportKey = `__vite_ssr_dynamic_import__`
export const ssrExportAllKey = `__vite_ssr_exportAll__`
export const ssrImportMetaKey = `__vite_ssr_import_meta__`

export async function ssrTransform(
code: string,
inMap: SourceMap | null,
url: string,
options?: TransformOptions
): Promise<TransformResult | null> {
if (options?.json?.stringify && isJSONRequest(url)) {
return ssrTransformJSON(code, inMap)
}
return ssrTransformScript(code, inMap, url)
}

async function ssrTransformJSON(
code: string,
inMap: SourceMap | null
): Promise<TransformResult> {
return {
code: code.replace('export default', `${ssrModuleExportsKey}.default =`),
map: inMap,
deps: [],
dynamicDeps: []
}
}

async function ssrTransformScript(
code: string,
inMap: SourceMap | null,
url: string
Expand Down
7 changes: 6 additions & 1 deletion playground/json/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
"dev": "vite",
"build": "vite build",
"debug": "node --inspect-brk ../../packages/vite/bin/vite",
"preview": "vite preview"
"preview": "vite preview",
"dev:ssr": "node server",
"serve:ssr": "cross-env NODE_ENV=production node server",
"debug:ssr": "node --inspect-brk server"
},
"devDependencies": {
"cross-env": "^7.0.3",
"express": "^4.17.1",
"json-module": "file:./json-module",
"vue": "^3.2.33"
}
Expand Down
4 changes: 4 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a709440

Please sign in to comment.