From a709440e26870580b8fd0da69f81d0d8ac5c788f Mon Sep 17 00:00:00 2001 From: yoho Date: Tue, 10 May 2022 21:37:02 +0800 Subject: [PATCH] fix(ssr): avoid transforming json file in ssrTransform (#6597) --- packages/playground/json/index.ssr.html | 23 +++++ packages/playground/json/server.js | 88 +++++++++++++++++++ packages/vite/src/node/plugins/json.ts | 7 +- packages/vite/src/node/server/index.ts | 6 +- .../vite/src/node/server/transformRequest.ts | 4 +- packages/vite/src/node/ssr/ssrModuleLoader.ts | 1 - packages/vite/src/node/ssr/ssrTransform.ts | 31 +++++++ playground/json/package.json | 7 +- pnpm-lock.yaml | 4 + 9 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 packages/playground/json/index.ssr.html create mode 100644 packages/playground/json/server.js diff --git a/packages/playground/json/index.ssr.html b/packages/playground/json/index.ssr.html new file mode 100644 index 00000000000000..8a4c4551a90817 --- /dev/null +++ b/packages/playground/json/index.ssr.html @@ -0,0 +1,23 @@ +
+ json-module: +

+  
+
+
+ json-fs: +

+  
+
+ + diff --git a/packages/playground/json/server.js b/packages/playground/json/server.js new file mode 100644 index 00000000000000..d7803b94f4b81a --- /dev/null +++ b/packages/playground/json/server.js @@ -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 diff --git a/packages/vite/src/node/plugins/json.ts b/packages/vite/src/node/plugins/json.ts index f8419c40f36174..9c142501ff651e 100644 --- a/packages/vite/src/node/plugins/json.ts +++ b/packages/vite/src/node/plugins/json.ts @@ -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 { /** @@ -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 diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 0b499b42c2d457..50ca05e17a748e 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -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) }, diff --git a/packages/vite/src/node/server/transformRequest.ts b/packages/vite/src/node/server/transformRequest.ts index baafe95e8416f3..f877925f491479 100644 --- a/packages/vite/src/node/server/transformRequest.ts +++ b/packages/vite/src/node/server/transformRequest.ts @@ -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, diff --git a/packages/vite/src/node/ssr/ssrModuleLoader.ts b/packages/vite/src/node/ssr/ssrModuleLoader.ts index 8b3a423f58aeab..9f75641c84e513 100644 --- a/packages/vite/src/node/ssr/ssrModuleLoader.ts +++ b/packages/vite/src/node/ssr/ssrModuleLoader.ts @@ -84,7 +84,6 @@ async function instantiateModule( if (mod.ssrModule) { return mod.ssrModule } - const result = mod.ssrTransformResult || (await transformRequest(url, server, { ssr: true })) diff --git a/packages/vite/src/node/ssr/ssrTransform.ts b/packages/vite/src/node/ssr/ssrTransform.ts index c1aa572864776a..4eeb34ad7e102c 100644 --- a/packages/vite/src/node/ssr/ssrTransform.ts +++ b/packages/vite/src/node/ssr/ssrTransform.ts @@ -12,6 +12,7 @@ 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 & { @@ -19,6 +20,12 @@ type Node = _Node & { 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__` @@ -26,6 +33,30 @@ 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 { + if (options?.json?.stringify && isJSONRequest(url)) { + return ssrTransformJSON(code, inMap) + } + return ssrTransformScript(code, inMap, url) +} + +async function ssrTransformJSON( + code: string, + inMap: SourceMap | null +): Promise { + return { + code: code.replace('export default', `${ssrModuleExportsKey}.default =`), + map: inMap, + deps: [], + dynamicDeps: [] + } +} + +async function ssrTransformScript( code: string, inMap: SourceMap | null, url: string diff --git a/playground/json/package.json b/playground/json/package.json index a32140c1220d1a..b919c42eb6ef5d 100644 --- a/playground/json/package.json +++ b/playground/json/package.json @@ -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" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 655b3273279f9e..1a06a82b104080 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -458,9 +458,13 @@ importers: playground/json: specifiers: + cross-env: ^7.0.3 + express: ^4.17.1 json-module: file:./json-module vue: ^3.2.33 devDependencies: + cross-env: 7.0.3 + express: 4.18.1 json-module: link:json-module vue: 3.2.33