diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3954ca49c11479..69ba432050fa7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: version: 6 - name: Set node version to ${{ matrix.node_version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node_version }} cache: "pnpm" @@ -82,7 +82,7 @@ jobs: version: 6 - name: Set node version to 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: 16 cache: "pnpm" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index eb8f4513707872..9e22af5aed6ee8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -23,7 +23,7 @@ jobs: version: 6 - name: Set node version to 16.x - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: 16.x registry-url: https://registry.npmjs.org/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000000..4abbb42e5ef159 --- /dev/null +++ b/.npmrc @@ -0,0 +1,7 @@ +hoist-pattern[]=*eslint* +hoist-pattern[]=*babel* +hoist-pattern[]=*jest* +hoist-pattern[]=@emotion/* +hoist-pattern[]=postcss +hoist-pattern[]=pug +hoist-pattern[]=source-map-support diff --git a/.prettierignore b/.prettierignore index 1692b9d26cfa20..c624a3a21eecfe 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,3 +10,4 @@ pnpm-lock.yaml pnpm-workspace.yaml packages/playground/tsconfig-json-load-error/has-error/tsconfig.json packages/playground/html/invalid.html +packages/playground/worker/classic-worker.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a0e5153f4b8ab..31c1f34f3a4815 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,22 @@ If you want to use break point and explore code execution you can use the ["Run 5. The execution will stop and you'll use the [Debug toolbar](https://code.visualstudio.com/docs/editor/debugging#_debug-actions) to continue, step over, restart the process... +### Debugging errors in Jest tests using Playwright (Chromium) + +Some errors are masked and hidden away because of the layers of abstraction and sandboxed nature added by Jest, Playwright, and Chromium. In order to see what's actually going wrong and the contents of the devtools console in those instances, follow this setup: + +1. Add a `debugger` statement to the `scripts/jestPerTestSetup.ts` -> `afterAll` hook. This will pause execution before the tests quit and the Playwright browser instance exits. + +1. Run the tests with the `debug-serve` script command which will enable remote debugging: `pnpm run debug-serve -- --runInBand resolve`. + +1. Wait for inspector devtools to open in your browser and the debugger to attach. + +1. In the sources panel in the right column, click the play button to resume execution and allow the tests to run which will open a Chromium instance. + +1. Focusing the Chomium instance, you can open the browser devtools and inspect the console there to find the underlying problems. + +1. To close everything, just stop the test process back in your terminal. + ## Testing Vite against external packages You may wish to test your locally-modified copy of Vite against another package that is built with Vite. For pnpm, after building Vite, you can use [`pnpm.overrides`](https://pnpm.io/package_json#pnpmoverrides). Please note that `pnpm.overrides` must be specified in the root `package.json` and you must first list the package as a dependency in the root `package.json`: diff --git a/docs/config/index.md b/docs/config/index.md index d4ee7a96a6fa67..ae70f469f1d445 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -96,6 +96,22 @@ export default defineConfig(async ({ command, mode }) => { }) ``` +### Environment Variables + +Vite doesn't load `.env` files by default as the files to load can only be determined after evaluating the Vite config, for example, the `root` and `envDir` options affects the loading behaviour. However, you can use the exported `loadEnv` helper to load the specific `.env` file if needed. + +```js +import { defineConfig, loadEnv } from 'vite' + +export default defineConfig(({ command, mode }) => { + // Load env file based on `mode` in the current working directory + const env = loadEnv(mode, process.cwd()) + return { + // build specific config + } +}) +``` + ## Shared Options ### root @@ -139,9 +155,11 @@ export default defineConfig(async ({ command, mode }) => { - Replacements are performed only when the match is surrounded by word boundaries (`\b`). + ::: warning Because it's implemented as straightforward text replacements without any syntax analysis, we recommend using `define` for CONSTANTS only. For example, `process.env.FOO` and `__APP_VERSION__` are good fits. But `process` or `global` should not be put into this option. Variables can be shimmed or polyfilled instead. + ::: ::: tip NOTE For TypeScript users, make sure to add the type declarations in the `env.d.ts` or `vite-env.d.ts` file to get type checks and Intellisense. @@ -508,12 +526,14 @@ export default defineConfig(async ({ command, mode }) => { ### server.hmr -- **Type:** `boolean | { protocol?: string, host?: string, port?: number, path?: string, timeout?: number, overlay?: boolean, clientPort?: number, server?: Server }` +- **Type:** `boolean | { protocol?: string, host?: string, port?: number | false, path?: string, timeout?: number, overlay?: boolean, clientPort?: number, server?: Server }` Disable or configure HMR connection (in cases where the HMR websocket must use a different address from the http server). Set `server.hmr.overlay` to `false` to disable the server error overlay. + Set `server.hmr.port` to `false` when connecting to a domain without a port. + `clientPort` is an advanced option that overrides the port only on the client side, allowing you to serve the websocket on a different port than the client code looks for it on. Useful if you're using an SSL proxy in front of your dev server. When using `server.middlewareMode` or `server.https`, assigning `server.hmr.server` to your HTTP(S) server will process HMR connection requests through your server. This can be helpful when using self-signed certificates or when you want to expose Vite over a network on a single port. diff --git a/docs/guide/build.md b/docs/guide/build.md index aac86a237b6819..a83e7a8d8b4452 100644 --- a/docs/guide/build.md +++ b/docs/guide/build.md @@ -43,6 +43,20 @@ module.exports = defineConfig({ For example, you can specify multiple Rollup outputs with plugins that are only applied during build. +## Chunking Strategy + +You can configure how chunks are split using `build.rollupOptions.manualChunks` (see [Rollup docs](https://rollupjs.org/guide/en/#outputmanualchunks)). Until Vite 2.7, the default chunking strategy divided the chunks into `index` and `vendor`. It is a good strategy for some SPAs, but it is hard to provide a general solution for every Vite target use case. From Vite 2.8, `manualChunks` is no longer modified by default. You can continue to use the Split Vendor Chunk strategy by adding the `splitVendorChunkPlugin` in your config file: + +```js +// vite.config.js +import { splitVendorChunkPlugin } from 'vite' +module.exports = defineConfig({ + plugins: [splitVendorChunkPlugin()] +}) +``` + +This strategy is also provided as a `splitVendorChunk({ cache: SplitVendorChunkCache })` factory, in case composition with custom logic is needed. `cache.reset()` needs to be called at `buildStart` for build watch mode to work correctly in this case. + ## Rebuild on files changes You can enable rollup watcher with `vite build --watch`. Or, you can directly adjust the underlying [`WatcherOptions`](https://rollupjs.org/guide/en/#watch-options) via `build.watch`: @@ -58,6 +72,8 @@ module.exports = defineConfig({ }) ``` +With the `--watch` flag enabled, changes to the `vite.config.js`, as well as any files to be bundled, will trigger a rebuild. + ## Multi-Page App Suppose you have the following source code structure: diff --git a/packages/playground/assets/__tests__/assets.spec.ts b/packages/playground/assets/__tests__/assets.spec.ts index dfdd8099b062a2..191da897858dd5 100644 --- a/packages/playground/assets/__tests__/assets.spec.ts +++ b/packages/playground/assets/__tests__/assets.spec.ts @@ -8,8 +8,7 @@ import { readManifest, readFile, editFile, - notifyRebuildComplete, - untilUpdated + notifyRebuildComplete } from '../../testUtils' const assetMatch = isBuild @@ -38,7 +37,7 @@ describe('injected scripts', () => { test('html-proxy', async () => { const hasHtmlProxy = await page.$( - 'script[type="module"][src^="/foo/index.html?html-proxy"]' + 'script[type="module"][src="/foo/index.html?html-proxy&index=0.js"]' ) if (isBuild) { expect(hasHtmlProxy).toBeFalsy() @@ -121,6 +120,10 @@ describe('css url() references', () => { const match = isBuild ? `data:image/png;base64` : `/foo/nested/icon.png` expect(await getBg('.css-url-base64-inline')).toMatch(match) expect(await getBg('.css-url-quotes-base64-inline')).toMatch(match) + const icoMatch = isBuild ? `data:image/x-icon;base64` : `favicon.ico` + const el = await page.$(`link.ico`) + const herf = await el.getAttribute('href') + expect(herf).toMatch(icoMatch) }) test('multiple urls on the same line', async () => { @@ -255,15 +258,3 @@ describe('css and assets in css in build watch', () => { }) } }) - -if (!isBuild) { - test('@import in html style tag hmr', async () => { - await untilUpdated(() => getColor('.import-css'), 'rgb(0, 136, 255)') - editFile( - './css/import.css', - (code) => code.replace('#0088ff', '#00ff88'), - true - ) - await untilUpdated(() => getColor('.import-css'), 'rgb(0, 255, 136)') - }) -} diff --git a/packages/playground/assets/favicon.ico b/packages/playground/assets/favicon.ico new file mode 100644 index 00000000000000..d75d248ef0b150 Binary files /dev/null and b/packages/playground/assets/favicon.ico differ diff --git a/packages/playground/assets/index.html b/packages/playground/assets/index.html index 8c5b201f6881a4..e33e9a7cdaaf7d 100644 --- a/packages/playground/assets/index.html +++ b/packages/playground/assets/index.html @@ -2,6 +2,7 @@
+ diff --git a/packages/playground/backend-integration/package.json b/packages/playground/backend-integration/package.json index afbdb63d356a8b..b3d9b064db16e2 100644 --- a/packages/playground/backend-integration/package.json +++ b/packages/playground/backend-integration/package.json @@ -10,5 +10,8 @@ }, "dependencies": { "tailwindcss": "^2.2.19" + }, + "devDependencies": { + "fast-glob": "^3.2.11" } } diff --git a/packages/playground/css/__tests__/postcss-plugins-different-dir.spec.ts b/packages/playground/css/__tests__/postcss-plugins-different-dir.spec.ts new file mode 100644 index 00000000000000..48500740b64613 --- /dev/null +++ b/packages/playground/css/__tests__/postcss-plugins-different-dir.spec.ts @@ -0,0 +1,29 @@ +import { getColor, getBgColor } from '../../testUtils' +import { createServer } from 'vite' +import path from 'path' + +// Regression test for https://github.com/vitejs/vite/issues/4000 +test('postcss plugins in different dir', async () => { + const port = 5005 + const server = await createServer({ + root: path.join(__dirname, '..', '..', 'tailwind'), + logLevel: 'silent', + server: { + port, + strictPort: true + }, + build: { + // skip transpilation during tests to make it faster + target: 'esnext' + } + }) + await server.listen() + try { + await page.goto(`http://localhost:${port}`) + const tailwindStyle = await page.$('.tailwind-style') + expect(await getBgColor(tailwindStyle)).toBe('rgb(254, 226, 226)') + expect(await getColor(tailwindStyle)).toBe('rgb(136, 136, 136)') + } finally { + await server.close() + } +}) diff --git a/packages/playground/css/package.json b/packages/playground/css/package.json index 13a58874578c09..b45063100be089 100644 --- a/packages/playground/css/package.json +++ b/packages/playground/css/package.json @@ -10,6 +10,7 @@ }, "devDependencies": { "css-dep": "link:./css-dep", + "fast-glob": "^3.2.11", "less": "^4.1.2", "postcss-nested": "^5.0.6", "sass": "^1.43.4", diff --git a/packages/playground/define/__tests__/define.spec.ts b/packages/playground/define/__tests__/define.spec.ts index f5eb78ea4e2766..93ba1ca198fbcc 100644 --- a/packages/playground/define/__tests__/define.spec.ts +++ b/packages/playground/define/__tests__/define.spec.ts @@ -20,4 +20,6 @@ test('string', async () => { expect(await page.textContent('.spread-array')).toBe( JSON.stringify([...defines.__STRING__]) ) + // html would't need to define replacement + expect(await page.textContent('.exp-define')).toBe('__EXP__') }) diff --git a/packages/playground/define/index.html b/packages/playground/define/index.html index bf6a9c59689396..4788ec9f2d2a57 100644 --- a/packages/playground/define/index.html +++ b/packages/playground/define/index.html @@ -9,6 +9,7 @@process as property:
spread object:
spread array:
define variable in html: __EXP__
fail
+fail
+ +fail
+fail
@@ -137,6 +148,12 @@new Worker(new Url('path', import.meta.url))
+new Worker(new Url('path', import.meta.url), { type: 'module' })
-new SharedWorker(new Url('path', import.meta.url))
+new SharedWorker(new Url('path', import.meta.url), { type: 'module' })
+new Worker(new Url('path', import.meta.url))
+ + +new Worker(new Url('path', import.meta.url), { type: 'classic' })
+ + ` - ) - } - await traverseHtml(html, htmlPath, (node) => { if (node.type !== NodeTypes.ELEMENT) { return @@ -135,16 +105,39 @@ const devHtmlHook: IndexHtmlTransformHook = async ( // script tags if (node.tag === 'script') { const { src, isModule } = getScriptInfo(node) + if (isModule) { + scriptModuleIndex++ + } if (src) { processNodeUrl(src, s, config, htmlPath, originalUrl, moduleGraph) } else if (isModule) { - addInlineModule(node, 'js') - } - } + const url = filePath.replace(normalizePath(config.root), '') + + const contents = node.children + .map((child: any) => child.content || '') + .join('') - if (node.tag === 'style' && node.children.length) { - addInlineModule(node, 'css') + // add HTML Proxy to Map + addToHTMLProxyCache(config, url, scriptModuleIndex, contents) + + // inline js module. convert to src="proxy" + const modulePath = `${ + config.base + htmlPath.slice(1) + }?html-proxy&index=${scriptModuleIndex}.js` + + // invalidate the module so the newly cached contents will be served + const module = server?.moduleGraph.getModuleById(modulePath) + if (module) { + server?.moduleGraph.invalidateModule(module) + } + + s.overwrite( + node.loc.start.offset, + node.loc.end.offset, + `` + ) + } } // elements with [href/src] attrs diff --git a/packages/vite/src/node/server/middlewares/static.ts b/packages/vite/src/node/server/middlewares/static.ts index 0b8e2db93255ed..a6623338783cc8 100644 --- a/packages/vite/src/node/server/middlewares/static.ts +++ b/packages/vite/src/node/server/middlewares/static.ts @@ -4,17 +4,17 @@ import type { Options } from 'sirv' import sirv from 'sirv' import type { Connect } from 'types/connect' import type { ViteDevServer } from '../..' -import { normalizePath } from '../..' import { FS_PREFIX } from '../../constants' import { cleanUrl, - ensureLeadingSlash, fsPathFromId, + fsPathFromUrl, isImportRequest, isInternalRequest, isWindows, slash, - isFileReadable + isFileReadable, + isParentDirectory } from '../../utils' import { isMatch } from 'micromatch' @@ -148,15 +148,14 @@ export function isFileServingAllowed( ): boolean { if (!server.config.server.fs.strict) return true - const cleanedUrl = cleanUrl(url) - const file = ensureLeadingSlash(normalizePath(cleanedUrl)) + const file = fsPathFromUrl(url) if (server.config.server.fs.deny.some((i) => isMatch(file, i, _matchOptions))) return false if (server.moduleGraph.safeModulesPath.has(file)) return true - if (server.config.server.fs.allow.some((i) => file.startsWith(i + '/'))) + if (server.config.server.fs.allow.some((dir) => isParentDirectory(dir, file))) return true return false diff --git a/packages/vite/src/node/server/middlewares/transform.ts b/packages/vite/src/node/server/middlewares/transform.ts index 15f2355e0e389c..ae7bec6e185113 100644 --- a/packages/vite/src/node/server/middlewares/transform.ts +++ b/packages/vite/src/node/server/middlewares/transform.ts @@ -1,3 +1,4 @@ +import { promises as fs } from 'fs' import path from 'path' import type { ViteDevServer } from '..' import type { Connect } from 'types/connect' @@ -11,28 +12,29 @@ import { prettifyUrl, removeImportQuery, removeTimestampQuery, - unwrapId + unwrapId, + fsPathFromId, + ensureVolumeInPath } from '../../utils' import { send } from '../send' import { transformRequest } from '../transformRequest' import { isHTMLProxy } from '../../plugins/html' import colors from 'picocolors' import { - CLIENT_PUBLIC_PATH, DEP_VERSION_RE, - NULL_BYTE_PLACEHOLDER + NULL_BYTE_PLACEHOLDER, + FS_PREFIX } from '../../constants' import { isCSSRequest, isDirectCSSRequest, isDirectRequest } from '../../plugins/css' - -/** - * Time (ms) Vite has to full-reload the page before returning - * an empty response. - */ -const NEW_DEPENDENCY_BUILD_TIMEOUT = 1000 +import { + ERR_OPTIMIZE_DEPS_PROCESSING_ERROR, + ERR_OUTDATED_OPTIMIZED_DEP +} from '../../plugins/optimizedDeps' +import { createIsOptimizedDepUrl } from '../../optimizer' const debugCache = createDebugger('vite:cache') const isDebug = !!process.env.DEBUG @@ -43,19 +45,11 @@ export function transformMiddleware( server: ViteDevServer ): Connect.NextHandleFunction { const { - config: { root, logger, cacheDir }, + config: { root, logger }, moduleGraph } = server - // determine the url prefix of files inside cache directory - const cacheDirRelative = normalizePath(path.relative(root, cacheDir)) - const cacheDirPrefix = cacheDirRelative.startsWith('../') - ? // if the cache directory is outside root, the url prefix would be something - // like '/@fs/absolute/path/to/node_modules/.vite' - `/@fs/${normalizePath(cacheDir).replace(/^\//, '')}` - : // if the cache directory is inside root, the url prefix would be something - // like '/node_modules/.vite' - `/${cacheDirRelative}` + const isOptimizedDepUrl = createIsOptimizedDepUrl(server.config) // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return async function viteTransformMiddleware(req, res, next) { @@ -63,36 +57,6 @@ export function transformMiddleware( return next() } - if ( - server._pendingReload && - // always allow vite client requests so that it can trigger page reload - !req.url?.startsWith(CLIENT_PUBLIC_PATH) && - !req.url?.includes('vite/dist/client') - ) { - try { - // missing dep pending reload, hold request until reload happens - await Promise.race([ - server._pendingReload, - // If the refresh has not happened after timeout, Vite considers - // something unexpected has happened. In this case, Vite - // returns an empty response that will error. - new Promise((_, reject) => - setTimeout(reject, NEW_DEPENDENCY_BUILD_TIMEOUT) - ) - ]) - } catch { - // Don't do anything if response has already been sent - if (!res.writableEnded) { - // status code request timeout - res.statusCode = 408 - res.end( - `The current page should have reloaded by now
` - ) - } - return - } - } let url: string try { url = decodeURI(removeTimestampQuery(req.url!)).replace( @@ -109,15 +73,47 @@ export function transformMiddleware( const isSourceMap = withoutQuery.endsWith('.map') // since we generate source map references, handle those requests here if (isSourceMap) { - const originalUrl = url.replace(/\.map($|\?)/, '$1') - const map = (await moduleGraph.getModuleByUrl(originalUrl, false)) - ?.transformResult?.map - if (map) { - return send(req, res, JSON.stringify(map), 'json', { - headers: server.config.server.headers - }) + if (isOptimizedDepUrl(url)) { + // If the browser is requesting a source map for an optimized dep, it + // means that the dependency has already been pre-bundled and loaded + const mapFile = url.startsWith(FS_PREFIX) + ? fsPathFromId(url) + : normalizePath( + ensureVolumeInPath(path.resolve(root, url.slice(1))) + ) + try { + const map = await fs.readFile(mapFile, 'utf-8') + return send(req, res, map, 'json', { + headers: server.config.server.headers + }) + } catch (e) { + // Outdated source map request for optimized deps, this isn't an error + // but part of the normal flow when re-optimizing after missing deps + // Send back an empty source map so the browser doesn't issue warnings + const dummySourceMap = { + version: 3, + file: mapFile.replace(/\.map$/, ''), + sources: [], + sourcesContent: [], + names: [], + mappings: ';;;;;;;;;' + } + return send(req, res, JSON.stringify(dummySourceMap), 'json', { + cacheControl: 'no-cache', + headers: server.config.server.headers + }) + } } else { - return next() + const originalUrl = url.replace(/\.map($|\?)/, '$1') + const map = (await moduleGraph.getModuleByUrl(originalUrl, false)) + ?.transformResult?.map + if (map) { + return send(req, res, JSON.stringify(map), 'json', { + headers: server.config.server.headers + }) + } else { + return next() + } } } @@ -179,9 +175,7 @@ export function transformMiddleware( }) if (result) { const type = isDirectCSSRequest(url) ? 'css' : 'js' - const isDep = - DEP_VERSION_RE.test(url) || - (cacheDirPrefix && url.startsWith(cacheDirPrefix)) + const isDep = DEP_VERSION_RE.test(url) || isOptimizedDepUrl(url) return send(req, res, result.code, type, { etag: result.etag, // allow browser to cache npm deps! @@ -192,6 +186,30 @@ export function transformMiddleware( } } } catch (e) { + if (e?.code === ERR_OPTIMIZE_DEPS_PROCESSING_ERROR) { + if (!res.writableEnded) { + // Don't do anything if response has already been sent + res.statusCode = 504 // status code request timeout + res.end() + } + // This timeout is unexpected + logger.error(e.message) + return + } + if (e?.code === ERR_OUTDATED_OPTIMIZED_DEP) { + if (!res.writableEnded) { + // Don't do anything if response has already been sent + res.statusCode = 504 // status code request timeout + res.end() + } + // We don't need to log an error in this case, the request + // is outdated because new dependencies were discovered and + // the new pre-bundle dependendencies have changed. + // A full-page reload has been issued, and these old requests + // can't be properly fullfilled. This isn't an unexpected + // error but a normal part of the missing deps discovery flow + return + } return next(e) } diff --git a/packages/vite/src/node/server/ws.ts b/packages/vite/src/node/server/ws.ts index 498148933740ef..c8da5e4ab6e82f 100644 --- a/packages/vite/src/node/server/ws.ts +++ b/packages/vite/src/node/server/ws.ts @@ -42,6 +42,7 @@ export function createWebSocketServer( } else { const websocketServerOptions: ServerOptions = {} const port = (hmr && hmr.port) || 24678 + const host = (hmr && hmr.host) || undefined if (httpsOptions) { // if we're serving the middlewares over https, the ws library doesn't support automatically creating an https server, so we need to do it ourselves // create an inline https server and mount the websocket server to it @@ -60,11 +61,14 @@ export function createWebSocketServer( res.end(body) }) - httpsServer.listen(port) + httpsServer.listen(port, host) websocketServerOptions.server = httpsServer } else { // we don't need to serve over https, just let ws handle its own server websocketServerOptions.port = port + if (host) { + websocketServerOptions.host = host + } } // vite dev server in middleware mode diff --git a/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts index f91444b49636a1..e086365ee25f16 100644 --- a/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts +++ b/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts @@ -304,8 +304,8 @@ test('should declare variable for imported super class', async () => { const Foo = __vite_ssr_import_0__.Foo; class A extends Foo {} class B extends Foo {} - Object.defineProperty(__vite_ssr_exports__, \\"default\\", { enumerable: true, value: A }); - Object.defineProperty(__vite_ssr_exports__, \\"B\\", { enumerable: true, configurable: true, get(){ return B }});" + Object.defineProperty(__vite_ssr_exports__, \\"B\\", { enumerable: true, configurable: true, get(){ return B }}); + Object.defineProperty(__vite_ssr_exports__, \\"default\\", { enumerable: true, value: A });" `) }) @@ -351,8 +351,8 @@ test('should handle default export variants', async () => { ).toMatchInlineSnapshot(` "class A {} class B extends A {} - Object.defineProperty(__vite_ssr_exports__, \\"default\\", { enumerable: true, value: A }); - Object.defineProperty(__vite_ssr_exports__, \\"B\\", { enumerable: true, configurable: true, get(){ return B }});" + Object.defineProperty(__vite_ssr_exports__, \\"B\\", { enumerable: true, configurable: true, get(){ return B }}); + Object.defineProperty(__vite_ssr_exports__, \\"default\\", { enumerable: true, value: A });" `) }) @@ -610,7 +610,7 @@ test('jsx', async () => { const code = ` import React from 'react' import { Foo, Slot } from 'foo' - + function Bar({ Slot =