From af2aa09575229462635b7cbb6d248ca853057ba2 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 16 Jan 2024 01:50:47 +0900 Subject: [PATCH] fix(ssr): externalize network imports during `ssrLoadModule` (#15599) --- .prettierignore | 1 + packages/vite/src/node/ssr/ssrModuleLoader.ts | 4 ++-- playground/ssr-html/__tests__/ssr-html.spec.ts | 15 +++++++++++++-- playground/ssr-html/public/slash@3.0.0.js | 5 +++++ playground/ssr-html/src/network-imports.js | 7 +++++++ playground/ssr-html/test-network-imports.js | 18 ++++++++++++++++++ 6 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 playground/ssr-html/public/slash@3.0.0.js create mode 100644 playground/ssr-html/src/network-imports.js create mode 100644 playground/ssr-html/test-network-imports.js diff --git a/.prettierignore b/.prettierignore index bc38eebdb55221..1fafdb547deccc 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,3 +9,4 @@ playground/tsconfig-json-load-error/has-error/tsconfig.json playground/html/invalid.html playground/html/valid.html playground/external/public/slash@3.0.0.js +playground/ssr-html/public/slash@3.0.0.js diff --git a/packages/vite/src/node/ssr/ssrModuleLoader.ts b/packages/vite/src/node/ssr/ssrModuleLoader.ts index 80830d08b383e1..e836d1e5f5f788 100644 --- a/packages/vite/src/node/ssr/ssrModuleLoader.ts +++ b/packages/vite/src/node/ssr/ssrModuleLoader.ts @@ -2,7 +2,7 @@ import path from 'node:path' import { pathToFileURL } from 'node:url' import colors from 'picocolors' import type { ViteDevServer } from '../server' -import { isBuiltin, isFilePathESM, unwrapId } from '../utils' +import { isBuiltin, isExternalUrl, isFilePathESM, unwrapId } from '../utils' import { transformRequest } from '../server/transformRequest' import type { InternalResolveOptionsWithOverrideConditions } from '../plugins/resolve' import { tryNodeResolve } from '../plugins/resolve' @@ -292,7 +292,7 @@ async function nodeImport( ) { let url: string let filePath: string | undefined - if (id.startsWith('data:') || isBuiltin(id)) { + if (id.startsWith('data:') || isExternalUrl(id) || isBuiltin(id)) { url = id } else { const resolved = tryNodeResolve( diff --git a/playground/ssr-html/__tests__/ssr-html.spec.ts b/playground/ssr-html/__tests__/ssr-html.spec.ts index 50b6e9540426bc..80fd5726d31411 100644 --- a/playground/ssr-html/__tests__/ssr-html.spec.ts +++ b/playground/ssr-html/__tests__/ssr-html.spec.ts @@ -1,6 +1,7 @@ import { execFile } from 'node:child_process' import { promisify } from 'node:util' import path from 'node:path' +import { fileURLToPath } from 'node:url' import fetch from 'node-fetch' import { describe, expect, test } from 'vitest' import { port } from './serve' @@ -62,9 +63,9 @@ describe.runIf(isServe)('hmr', () => { }) }) -describe.runIf(isServe)('stacktrace', () => { - const execFileAsync = promisify(execFile) +const execFileAsync = promisify(execFile) +describe.runIf(isServe)('stacktrace', () => { for (const ext of ['js', 'ts']) { for (const sourcemapsEnabled of [false, true]) { test(`stacktrace of ${ext} is correct when sourcemaps is${ @@ -98,3 +99,13 @@ describe.runIf(isServe)('stacktrace', () => { } } }) + +test.runIf(isServe)('network-imports', async () => { + await execFileAsync( + 'node', + ['--experimental-network-imports', 'test-network-imports.js'], + { + cwd: fileURLToPath(new URL('..', import.meta.url)), + }, + ) +}) diff --git a/playground/ssr-html/public/slash@3.0.0.js b/playground/ssr-html/public/slash@3.0.0.js new file mode 100644 index 00000000000000..754082e97c4f82 --- /dev/null +++ b/playground/ssr-html/public/slash@3.0.0.js @@ -0,0 +1,5 @@ +/* eslint-disable */ +// copied from https://esm.sh/v133/slash@3.0.0/es2022/slash.mjs to reduce network issues in CI + +/* esm.sh - esbuild bundle(slash@3.0.0) es2022 production */ +var a=Object.create;var d=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty;var A=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),E=(e,t)=>{for(var r in t)d(e,r,{get:t[r],enumerable:!0})},u=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of x(t))!p.call(e,n)&&n!==r&&d(e,n,{get:()=>t[n],enumerable:!(i=m(t,n))||i.enumerable});return e},o=(e,t,r)=>(u(e,t,"default"),r&&u(r,t,"default")),c=(e,t,r)=>(r=e!=null?a(g(e)):{},u(t||!e||!e.__esModule?d(r,"default",{value:e,enumerable:!0}):r,e));var f=A((h,_)=>{"use strict";_.exports=e=>{let t=/^\\\\\?\\/.test(e),r=/[^\u0000-\u0080]+/.test(e);return t||r?e:e.replace(/\\/g,"/")}});var s={};E(s,{default:()=>P});var L=c(f());o(s,c(f()));var{default:l,...N}=L,P=l!==void 0?l:N;export{P as default}; diff --git a/playground/ssr-html/src/network-imports.js b/playground/ssr-html/src/network-imports.js new file mode 100644 index 00000000000000..770fb6e57b610d --- /dev/null +++ b/playground/ssr-html/src/network-imports.js @@ -0,0 +1,7 @@ +// same port as `ports["ssr-html"]` in playground/test-utils.ts +import slash from 'http://localhost:9602/slash@3.0.0.js' + +// or test without local server +// import slash from 'https://esm.sh/slash@3.0.0' + +export { slash } diff --git a/playground/ssr-html/test-network-imports.js b/playground/ssr-html/test-network-imports.js new file mode 100644 index 00000000000000..ddb80eff7f8ca7 --- /dev/null +++ b/playground/ssr-html/test-network-imports.js @@ -0,0 +1,18 @@ +import assert from 'node:assert' +import { fileURLToPath } from 'node:url' +import { createServer } from 'vite' + +async function runTest() { + const server = await createServer({ + configFile: false, + root: fileURLToPath(new URL('.', import.meta.url)), + server: { + middlewareMode: true, + }, + }) + const mod = await server.ssrLoadModule('/src/network-imports.js') + assert.equal(mod.slash('foo\\bar'), 'foo/bar') + await server.close() +} + +runTest()