Skip to content

Commit

Permalink
fix(ssr): handle virtual modules during ssr
Browse files Browse the repository at this point in the history
fix #1980
  • Loading branch information
yyx990803 committed Feb 11, 2021
1 parent 416f190 commit 108be94
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 25 deletions.
4 changes: 4 additions & 0 deletions packages/playground/ssr-vue/__tests__/ssr-vue.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ test('jsx', async () => {
expect(await page.textContent('.jsx')).toMatch('from JSX')
})

test('virtual module', async () => {
expect(await page.textContent('.virtual')).toMatch('hi')
})

test('hydration', async () => {
expect(await page.textContent('button')).toMatch('0')
await page.click('button')
Expand Down
2 changes: 2 additions & 0 deletions packages/playground/ssr-vue/src/pages/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
</p>
<button @click="state.count++">count is: {{ state.count }}</button>
<Foo />
<p class="virtual">msg from virtual module: {{ foo.msg }}</p>
</template>

<script setup>
import foo from '@foo'
import { reactive, defineAsyncComponent } from 'vue'
const Foo = defineAsyncComponent(() => import('../components/Foo').then(mod => mod.Foo))
Expand Down
18 changes: 17 additions & 1 deletion packages/playground/ssr-vue/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,23 @@ const vueJsx = require('@vitejs/plugin-vue-jsx')
* @type {import('vite').UserConfig}
*/
module.exports = {
plugins: [vuePlugin(), vueJsx()],
plugins: [
vuePlugin(),
vueJsx(),
{
name: 'virtual',
resolveId(id) {
if (id === '@foo') {
return id
}
},
load(id) {
if (id === '@foo') {
return `export default { msg: 'hi' }`
}
}
}
],
build: {
minify: false
}
Expand Down
27 changes: 13 additions & 14 deletions packages/vite/src/node/plugins/importAnalysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,25 +203,24 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
VALID_ID_PREFIX + resolved.id.replace('\0', NULL_BYTE_PLACEHOLDER)
}

// mark non-js/css imports with `?import`
// make the URL browser-valid if not SSR
if (!ssr) {
// mark non-js/css imports with `?import`
url = markExplicitImport(url)
}

// for relative js/css imports, inherit importer's version query
// do not do this for unknown type imports, otherwise the appended
// query can break 3rd party plugin's extension checks.
if (isRelative && !/[\?&]import\b/.test(url)) {
const versionMatch = importer.match(DEP_VERSION_RE)
if (versionMatch) {
url = injectQuery(url, versionMatch[1])
// for relative js/css imports, inherit importer's version query
// do not do this for unknown type imports, otherwise the appended
// query can break 3rd party plugin's extension checks.
if (isRelative && !/[\?&]import\b/.test(url)) {
const versionMatch = importer.match(DEP_VERSION_RE)
if (versionMatch) {
url = injectQuery(url, versionMatch[1])
}
}
}

// check if the dep has been hmr updated. If yes, we need to attach
// its last updated timestamp to force the browser to fetch the most
// up-to-date version of this module.
if (!ssr) {
// check if the dep has been hmr updated. If yes, we need to attach
// its last updated timestamp to force the browser to fetch the most
// up-to-date version of this module.
try {
const depModule = await moduleGraph.ensureEntryFromUrl(url)
if (depModule.lastHMRTimestamp > 0) {
Expand Down
11 changes: 4 additions & 7 deletions packages/vite/src/node/server/middlewares/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
isJSRequest,
prettifyUrl,
removeImportQuery,
removeTimestampQuery
removeTimestampQuery,
unwrapId
} from '../../utils'
import { send } from '../send'
import { transformRequest } from '../transformRequest'
Expand All @@ -18,8 +19,7 @@ import {
CLIENT_PUBLIC_PATH,
DEP_CACHE_DIR,
DEP_VERSION_RE,
NULL_BYTE_PLACEHOLDER,
VALID_ID_PREFIX
NULL_BYTE_PLACEHOLDER
} from '../../constants'
import { isCSSRequest, isDirectCSSRequest } from '../../plugins/css'

Expand Down Expand Up @@ -111,12 +111,9 @@ export function transformMiddleware(
) {
// strip ?import
url = removeImportQuery(url)

// Strip valid id prefix. This is preprended to resolved Ids that are
// not valid browser import specifiers by the importAnalysis plugin.
if (url.startsWith(VALID_ID_PREFIX)) {
url = url.slice(VALID_ID_PREFIX.length)
}
url = unwrapId(url)

// for CSS, we need to differentiate between normal CSS requests and
// imports
Expand Down
6 changes: 4 additions & 2 deletions packages/vite/src/node/ssr/ssrModuleLoader.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs'
import path from 'path'
import { ViteDevServer } from '..'
import { cleanUrl, resolveFrom } from '../utils'
import { cleanUrl, resolveFrom, unwrapId } from '../utils'
import { ssrRewriteStacktrace } from './ssrStacktrace'
import {
ssrExportAllKey,
Expand All @@ -23,6 +23,8 @@ export async function ssrLoadModule(
context: SSRContext = { global: isolated ? Object.create(global) : global },
urlStack: string[] = []
): Promise<Record<string, any>> {
url = unwrapId(url)

if (urlStack.includes(url)) {
server.config.logger.warn(
`Circular dependency: ${urlStack.join(' -> ')} -> ${url}`
Expand Down Expand Up @@ -72,7 +74,7 @@ export async function ssrLoadModule(
if (isExternal(dep)) {
return nodeRequire(dep, mod.file, server.config.root)
} else {
return moduleGraph.urlToModuleMap.get(dep)?.ssrModule
return moduleGraph.urlToModuleMap.get(unwrapId(dep))?.ssrModule
}
}

Expand Down
8 changes: 7 additions & 1 deletion packages/vite/src/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fs from 'fs'
import os from 'os'
import path from 'path'
import { parse as parseUrl } from 'url'
import { FS_PREFIX, DEFAULT_EXTENSIONS } from './constants'
import { FS_PREFIX, DEFAULT_EXTENSIONS, VALID_ID_PREFIX } from './constants'
import resolve from 'resolve'
import builtins from 'builtin-modules'
import { FSWatcher } from 'chokidar'
Expand All @@ -13,6 +13,12 @@ export function slash(p: string): string {
return p.replace(/\\/g, '/')
}

// Strip valid id prefix. This is preprended to resolved Ids that are
// not valid browser import specifiers by the importAnalysis plugin.
export function unwrapId(id: string): string {
return id.startsWith(VALID_ID_PREFIX) ? id.slice(VALID_ID_PREFIX.length) : id
}

export const flattenId = (id: string) => id.replace(/[\/\.]/g, '_')

export function isBuiltin(id: string): boolean {
Expand Down

0 comments on commit 108be94

Please sign in to comment.