From f36fcd234d61b4b133667bda8f25c85d9687384d Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Sun, 29 Oct 2023 14:06:16 +0800 Subject: [PATCH 01/11] fix(define): correctly replace same define values (#14786) --- .../vite/src/node/__tests__/plugins/define.spec.ts | 11 ++++++++++- packages/vite/src/node/plugins/define.ts | 10 ---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/define.spec.ts b/packages/vite/src/node/__tests__/plugins/define.spec.ts index de9d4b36b742c6..2ac85712b2a072 100644 --- a/packages/vite/src/node/__tests__/plugins/define.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/define.spec.ts @@ -50,7 +50,16 @@ describe('definePlugin', () => { 'import.meta.hot': 'import.meta.hot', }) expect(await overrideTransform('const hot = import.meta.hot;')).toBe( - undefined, + 'const hot = import.meta.hot;\n', + ) + }) + + test('preserve import.meta.env.UNKNOWN with override', async () => { + const transform = await createDefinePluginTransform({ + 'import.meta.env.UNKNOWN': 'import.meta.env.UNKNOWN', + }) + expect(await transform('const foo = import.meta.env.UNKNOWN;')).toBe( + 'const foo = import.meta.env.UNKNOWN;\n', ) }) }) diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index 36b0df05a9b55a..ccd6a5571a6e39 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -49,16 +49,6 @@ export function definePlugin(config: ResolvedConfig): Plugin { const userDefine: Record = {} const userDefineEnv: Record = {} for (const key in config.define) { - // user can define keys with the same values to declare that some keys - // should not be replaced. in this case, we delete references of the key - // so they aren't replaced in the first place. - const val = config.define[key] - if (key === val) { - delete processNodeEnv[key] - delete importMetaKeys[key] - continue - } - userDefine[key] = handleDefineValue(config.define[key]) // make sure `import.meta.env` object has user define properties From ac5d8a7745776f6d7921a110ac650ab48037debf Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Sun, 29 Oct 2023 18:35:34 +0800 Subject: [PATCH 02/11] chore: update license (#14790) --- packages/vite/LICENSE.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/vite/LICENSE.md b/packages/vite/LICENSE.md index 286af89af35c42..03b0ef717114e4 100644 --- a/packages/vite/LICENSE.md +++ b/packages/vite/LICENSE.md @@ -528,6 +528,28 @@ License: MIT By: LarsDenBakker Repository: rollup/plugins +> The MIT License (MIT) +> +> Copyright (c) 2019 RollupJS Plugin Contributors (https://github.com/rollup/plugins/graphs/contributors) +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. + --------------------------------------- ## @rollup/pluginutils From 17fb5ee41f96e3e4aefc6d6258436676de048686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Mon, 30 Oct 2023 06:04:16 +0900 Subject: [PATCH 03/11] feat: add a runtime warning for the old object type transformIndexHtml hook (#14791) --- packages/vite/src/node/plugins/html.ts | 18 ++++++++++++++++++ .../src/node/server/middlewares/indexHtml.ts | 1 + 2 files changed, 19 insertions(+) diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 94141ec0c237a4..a56927d14b992f 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -26,6 +26,7 @@ import { import type { ResolvedConfig } from '../config' import { toOutputFilePathInHtml } from '../build' import { resolveEnvPrefix } from '../env' +import type { Logger } from '../logger' import { assetUrlRE, checkPublicFile, @@ -287,6 +288,7 @@ function handleParseError( export function buildHtmlPlugin(config: ResolvedConfig): Plugin { const [preHooks, normalHooks, postHooks] = resolveHtmlTransforms( config.plugins, + config.logger, ) preHooks.unshift(preImportMapHook(config)) preHooks.push(htmlEnvHook(config)) @@ -1066,6 +1068,7 @@ export function htmlEnvHook(config: ResolvedConfig): IndexHtmlTransformHook { export function resolveHtmlTransforms( plugins: readonly Plugin[], + logger: Logger, ): [ IndexHtmlTransformHook[], IndexHtmlTransformHook[], @@ -1082,6 +1085,21 @@ export function resolveHtmlTransforms( if (typeof hook === 'function') { normalHooks.push(hook) } else { + if (!('order' in hook) && 'enforce' in hook) { + logger.warnOnce( + colors.yellow( + `plugin '${plugin.name}' uses deprecated 'enforce' option. Use 'order' option instead.`, + ), + ) + } + if (!('handler' in hook) && 'transform' in hook) { + logger.warnOnce( + colors.yellow( + `plugin '${plugin.name}' uses deprecated 'transform' option. Use 'handler' option instead.`, + ), + ) + } + // `enforce` had only two possible values for the `transformIndexHtml` hook // `'pre'` and `'post'` (the default). `order` now works with three values // to align with other hooks (`'pre'`, normal, and `'post'`). We map diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts index cef336adce2cf6..c25aaa3f02e3ee 100644 --- a/packages/vite/src/node/server/middlewares/indexHtml.ts +++ b/packages/vite/src/node/server/middlewares/indexHtml.ts @@ -63,6 +63,7 @@ export function createDevHtmlTransformFn( ): (url: string, html: string, originalUrl: string) => Promise { const [preHooks, normalHooks, postHooks] = resolveHtmlTransforms( server.config.plugins, + server.config.logger, ) return (url: string, html: string, originalUrl: string): Promise => { return applyHtmlTransforms( From deb5515c282c9fab52450a450848390333e2fef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Mon, 30 Oct 2023 11:54:20 +0900 Subject: [PATCH 04/11] refactor!: remove non boolean middleware mode (#14792) --- docs/guide/migration.md | 1 + packages/vite/src/node/config.ts | 24 +++--------------------- packages/vite/src/node/server/index.ts | 2 +- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/docs/guide/migration.md b/docs/guide/migration.md index 181415d3c92102..a1510c98ca9994 100644 --- a/docs/guide/migration.md +++ b/docs/guide/migration.md @@ -150,6 +150,7 @@ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) - Default exports of CSS files (e.g `import style from './foo.css'`): Use the `?inline` query instead - `import.meta.globEager`: Use `import.meta.glob('*', { eager: true })` instead - `ssr.format: 'cjs'` and `legacy.buildSsrCjsExternalHeuristics` ([#13816](https://github.com/vitejs/vite/discussions/13816)) +- `server.middlewareMode: 'ssr'` and `server.middlewareMode: 'html'`: Use [`appType`](/config/shared-options.md#apptype) + [`server.middlewareMode: true`](/config/server-options.md#server-middlewaremode) instead ([#8452](https://github.com/vitejs/vite/pull/8452)) ## Advanced diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index e923e9c348ec10..207b949cc7e83c 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -670,8 +670,6 @@ export async function resolveConfig( const server = resolveServerOptions(resolvedRoot, config.server, logger) const ssr = resolveSSROptions(config.ssr, resolveOptions.preserveSymlinks) - const middlewareMode = config?.server?.middlewareMode - const optimizeDeps = config.optimizeDeps || {} const BASE_URL = resolvedBase @@ -796,7 +794,7 @@ export async function resolveConfig( }, }, worker: resolvedWorkerOptions, - appType: config.appType ?? (middlewareMode === 'ssr' ? 'custom' : 'spa'), + appType: config.appType ?? 'spa', experimental: { importGlobRestoreExtension: false, hmrPartialAccept: false, @@ -824,24 +822,6 @@ export async function resolveConfig( .map((hook) => hook(resolved)), ) - // validate config - - if (middlewareMode === 'ssr') { - logger.warn( - colors.yellow( - `Setting server.middlewareMode to 'ssr' is deprecated, set server.middlewareMode to \`true\`${ - config.appType === 'custom' ? '' : ` and appType to 'custom'` - } instead`, - ), - ) - } else if (middlewareMode === 'html') { - logger.warn( - colors.yellow( - `Setting server.middlewareMode to 'html' is deprecated, set server.middlewareMode to \`true\` instead`, - ), - ) - } - debug?.(`using resolved config: %O`, { ...resolved, plugins: resolved.plugins.map((p) => p.name), @@ -851,6 +831,8 @@ export async function resolveConfig( }, }) + // validate config + if (config.build?.terserOptions && config.build.minify !== 'terser') { logger.warn( colors.yellow( diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 20dfdad6be6363..e58dc4d1e3ea47 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -108,7 +108,7 @@ export interface ServerOptions extends CommonServerOptions { * Create Vite dev server to be used as a middleware in an existing server * @default false */ - middlewareMode?: boolean | 'html' | 'ssr' + middlewareMode?: boolean /** * Options for files served via '/\@fs/'. */ From af0446be4f51ffb927877d255dd06cb4fa7344f2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 10:55:21 +0800 Subject: [PATCH 05/11] chore(deps): update actions/setup-node action to v4 (#14796) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- .github/workflows/publish.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e451f4b248047..cb90d098eb1d47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,7 +73,7 @@ jobs: - name: Set node version to ${{ matrix.node_version }} if: steps.changed-files.outputs.only_changed != 'true' - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node_version }} cache: "pnpm" @@ -137,7 +137,7 @@ jobs: uses: pnpm/action-setup@v2.4.0 - name: Set node version to 18 - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: "pnpm" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b539389034eadc..e78141ef129140 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -24,7 +24,7 @@ jobs: uses: pnpm/action-setup@v2.4.0 - name: Set node version to 18 - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 registry-url: https://registry.npmjs.org/ From 788145790e7652d715575d7a0bc33a825b49d566 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 10:56:26 +0800 Subject: [PATCH 06/11] chore(deps): update dependency eslint-plugin-react-refresh to ^0.4.4 (#14795) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/create-vite/template-react-ts/package.json | 2 +- packages/create-vite/template-react/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/create-vite/template-react-ts/package.json b/packages/create-vite/template-react-ts/package.json index 52f11c09e2fd83..9bc5e3858211d1 100644 --- a/packages/create-vite/template-react-ts/package.json +++ b/packages/create-vite/template-react-ts/package.json @@ -21,7 +21,7 @@ "@vitejs/plugin-react": "^4.1.0", "eslint": "^8.52.0", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.3", + "eslint-plugin-react-refresh": "^0.4.4", "typescript": "^5.2.2", "vite": "^5.0.0-beta.13" } diff --git a/packages/create-vite/template-react/package.json b/packages/create-vite/template-react/package.json index 266aaf8691bf36..f3fd48fea70e9d 100644 --- a/packages/create-vite/template-react/package.json +++ b/packages/create-vite/template-react/package.json @@ -20,7 +20,7 @@ "eslint": "^8.52.0", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.3", + "eslint-plugin-react-refresh": "^0.4.4", "vite": "^5.0.0-beta.13" } } From a090742a6528aa2eff88226d411d821de5b12e94 Mon Sep 17 00:00:00 2001 From: lzt1008 <75012451+lzt1008@users.noreply.github.com> Date: Mon, 30 Oct 2023 21:47:22 +0800 Subject: [PATCH 07/11] chore(shortcuts): resolve generic type error (#14802) Co-authored-by: liangzhengtai --- packages/vite/src/node/shortcuts.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/vite/src/node/shortcuts.ts b/packages/vite/src/node/shortcuts.ts index 0a382c25b93c0c..9b3671dbee8cf4 100644 --- a/packages/vite/src/node/shortcuts.ts +++ b/packages/vite/src/node/shortcuts.ts @@ -46,9 +46,11 @@ export function bindCLIShortcuts( ) } - const shortcuts = (opts?.customShortcuts ?? []) - // @ts-expect-error passing the right types, but typescript can't detect it - .concat(isDev ? BASE_DEV_SHORTCUTS : BASE_PREVIEW_SHORTCUTS) + const shortcuts = (opts?.customShortcuts ?? []).concat( + (isDev + ? BASE_DEV_SHORTCUTS + : BASE_PREVIEW_SHORTCUTS) as CLIShortcut[], + ) let actionRunning = false From 4f71ae8736ff5d2fc9eca876825d16b0c4402720 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Mon, 30 Oct 2023 21:57:15 +0800 Subject: [PATCH 08/11] fix(html)!: align html serving between dev and preview (#14756) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 翠 / green --- docs/guide/migration.md | 25 +++- packages/vite/LICENSE.md | 29 ----- packages/vite/package.json | 1 - packages/vite/src/node/preview.ts | 25 +++- packages/vite/src/node/server/index.ts | 9 +- .../node/server/middlewares/htmlFallback.ts | 108 ++++++++++++------ .../src/node/server/middlewares/indexHtml.ts | 31 +++-- .../src/node/server/middlewares/notFound.ts | 9 ++ packages/vite/src/node/shortcuts.ts | 7 +- packages/vite/src/node/utils.ts | 7 ++ packages/vite/src/types/shims.d.ts | 5 - playground/assets/__tests__/assets.spec.ts | 8 +- playground/html/__tests__/html.spec.ts | 59 ++++++++++ playground/html/index.html | 1 + playground/html/serve/both.html | 1 + playground/html/serve/both/index.html | 1 + playground/html/serve/file.html | 1 + playground/html/serve/folder/index.html | 1 + playground/html/vite.config.js | 4 + playground/legacy/__tests__/legacy.spec.ts | 10 +- pnpm-lock.yaml | 8 -- 21 files changed, 236 insertions(+), 114 deletions(-) create mode 100644 packages/vite/src/node/server/middlewares/notFound.ts create mode 100644 playground/html/serve/both.html create mode 100644 playground/html/serve/both/index.html create mode 100644 playground/html/serve/file.html create mode 100644 playground/html/serve/folder/index.html diff --git a/docs/guide/migration.md b/docs/guide/migration.md index a1510c98ca9994..16f63bdceb2e57 100644 --- a/docs/guide/migration.md +++ b/docs/guide/migration.md @@ -102,10 +102,29 @@ In Vite 4, `worker.plugins` accepted an array of plugins (`(Plugin | Plugin[])[] ### Allow path containing `.` to fallback to index.html -In Vite 4, accessing a path containing `.` did not fallback to index.html even if `appType` is set to `'SPA'` (default). -From Vite 5, it will fallback to index.html. +In Vite 4, accessing a path in dev containing `.` did not fallback to index.html even if `appType` is set to `'spa'` (default). From Vite 5, it will fallback to index.html. -Note that the browser will no longer show the 404 error message in the console if you point the image path to a non-existent file (e.g. ``). +Note that the browser will no longer show a 404 error message in the console if you point the image path to a non-existent file (e.g. ``). + +### Align dev and preview HTML serving behaviour + +In Vite 4, the dev and preview servers serve HTML based on its directory structure and trailing slash differently. This causes inconsistencies when testing your built app. Vite 5 refactors into a single behaviour like below, given the following file structure: + +``` +├── index.html +├── file.html +└── dir + └── index.html +``` + +| Request | Before (dev) | Before (preview) | After (dev & preview) | +| ----------------- | ---------------------------- | ----------------- | ---------------------------- | +| `/dir/index.html` | `/dir/index.html` | `/dir/index.html` | `/dir/index.html` | +| `/dir` | `/index.html` (SPA fallback) | `/dir/index.html` | `/dir.html` (SPA fallback) | +| `/dir/` | `/dir/index.html` | `/dir/index.html` | `/dir/index.html` | +| `/file.html` | `/file.html` | `/file.html` | `/file.html` | +| `/file` | `/index.html` (SPA fallback) | `/file.html` | `/file.html` | +| `/file/` | `/index.html` (SPA fallback) | `/file.html` | `/index.html` (SPA fallback) | ### Manifest files are now generated in `.vite` directory by default diff --git a/packages/vite/LICENSE.md b/packages/vite/LICENSE.md index 03b0ef717114e4..7b45e464cf268f 100644 --- a/packages/vite/LICENSE.md +++ b/packages/vite/LICENSE.md @@ -911,35 +911,6 @@ Repository: senchalabs/connect --------------------------------------- -## connect-history-api-fallback -License: MIT -By: Ben Ripkens, Craig Myles -Repository: http://github.com/bripkens/connect-history-api-fallback.git - -> The MIT License -> -> Copyright (c) 2022 Ben Blackmore and contributors -> -> Permission is hereby granted, free of charge, to any person obtaining a copy -> of this software and associated documentation files (the "Software"), to deal -> in the Software without restriction, including without limitation the rights -> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -> copies of the Software, and to permit persons to whom the Software is -> furnished to do so, subject to the following conditions: -> -> The above copyright notice and this permission notice shall be included in -> all copies or substantial portions of the Software. -> -> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -> THE SOFTWARE. - ---------------------------------------- - ## convert-source-map License: MIT By: Thorsten Lorenz diff --git a/packages/vite/package.json b/packages/vite/package.json index 1606719790f67f..831a138585f27f 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -98,7 +98,6 @@ "cac": "^6.7.14", "chokidar": "^3.5.3", "connect": "^3.7.0", - "connect-history-api-fallback": "^2.0.0", "convert-source-map": "^2.0.0", "cors": "^2.8.5", "cross-spawn": "^7.0.3", diff --git a/packages/vite/src/node/preview.ts b/packages/vite/src/node/preview.ts index e678bc6341d658..3d9329e581f3d8 100644 --- a/packages/vite/src/node/preview.ts +++ b/packages/vite/src/node/preview.ts @@ -15,6 +15,9 @@ import { } from './http' import { openBrowser } from './server/openBrowser' import compression from './server/middlewares/compression' +import { htmlFallbackMiddleware } from './server/middlewares/htmlFallback' +import { indexHtmlMiddleware } from './server/middlewares/indexHtml' +import { notFoundMiddleware } from './server/middlewares/notFound' import { proxyMiddleware } from './server/middlewares/proxy' import { resolveHostname, resolveServerUrls, shouldServeFile } from './utils' import { printServerUrls } from './logger' @@ -170,7 +173,7 @@ export async function preview( sirv(distDir, { etag: true, dev: true, - single: config.appType === 'spa', + extensions: [], ignores: false, setHeaders(res) { if (headers) { @@ -186,9 +189,29 @@ export async function preview( app.use(previewBase, viteAssetMiddleware) + // html fallback + if (config.appType === 'spa' || config.appType === 'mpa') { + app.use( + previewBase, + htmlFallbackMiddleware( + distDir, + config.appType === 'spa', + previewBase !== '/', + ), + ) + } + // apply post server hooks from plugins postHooks.forEach((fn) => fn && fn()) + if (config.appType === 'spa' || config.appType === 'mpa') { + // transform index.html + app.use(previewBase, indexHtmlMiddleware(distDir, server)) + + // handle 404s + app.use(previewBase, notFoundMiddleware()) + } + const hostname = await resolveHostname(options.host) const port = options.port ?? DEFAULT_PREVIEW_PORT const protocol = options.https ? 'https' : 'http' diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index e58dc4d1e3ea47..25b1e4efd0e7a4 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -66,6 +66,7 @@ import { import { timeMiddleware } from './middlewares/time' import type { ModuleNode } from './moduleGraph' import { ModuleGraph } from './moduleGraph' +import { notFoundMiddleware } from './middlewares/notFound' import { errorMiddleware, prepareError } from './middlewares/error' import type { HmrOptions } from './hmr' import { @@ -692,14 +693,10 @@ export async function _createServer( if (config.appType === 'spa' || config.appType === 'mpa') { // transform index.html - middlewares.use(indexHtmlMiddleware(server)) + middlewares.use(indexHtmlMiddleware(root, server)) // handle 404s - // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` - middlewares.use(function vite404Middleware(_, res) { - res.statusCode = 404 - res.end() - }) + middlewares.use(notFoundMiddleware()) } // error handler diff --git a/packages/vite/src/node/server/middlewares/htmlFallback.ts b/packages/vite/src/node/server/middlewares/htmlFallback.ts index 39bf8ae2e32e17..85f5e396e54f8c 100644 --- a/packages/vite/src/node/server/middlewares/htmlFallback.ts +++ b/packages/vite/src/node/server/middlewares/htmlFallback.ts @@ -1,48 +1,86 @@ import fs from 'node:fs' import path from 'node:path' -import history from 'connect-history-api-fallback' import type { Connect } from 'dep-types/connect' -import { createDebugger } from '../../utils' +import { cleanUrl, createDebugger } from '../../utils' + +const debug = createDebugger('vite:html-fallback') export function htmlFallbackMiddleware( root: string, spaFallback: boolean, + mounted = false, ): Connect.NextHandleFunction { - const historyHtmlFallbackMiddleware = history({ - disableDotRule: true, - logger: createDebugger('vite:html-fallback'), - rewrites: [ - // support /dir/ without explicit index.html - { - from: /\/$/, - to({ parsedUrl, request }: any) { - const rewritten = - decodeURIComponent(parsedUrl.pathname) + 'index.html' - - if (fs.existsSync(path.join(root, rewritten))) { - return rewritten - } - - return spaFallback ? `/index.html` : request.url - }, - }, - { - from: /\.html$/, - to({ parsedUrl, request }: any) { - // .html files are not handled by serveStaticMiddleware - // so we need to check if the file exists - const pathname = decodeURIComponent(parsedUrl.pathname) - if (fs.existsSync(path.join(root, pathname))) { - return request.url - } - return spaFallback ? `/index.html` : request.url - }, - }, - ], - }) + // When this middleware is mounted on a route, we need to re-assign `req.url` with a + // leading `.` to signal a relative rewrite. Returning with a leading `/` returns a + // buggy `req.url`. e.g.: + // + // mount /foo/bar: + // req.url = /index.html + // final = /foo/barindex.html + // + // mount /foo/bar: + // req.url = ./index.html + // final = /foo/bar/index.html + const prepend = mounted ? '.' : '' // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return function viteHtmlFallbackMiddleware(req, res, next) { - return historyHtmlFallbackMiddleware(req, res, next) + if ( + // Only accept GET or HEAD + (req.method !== 'GET' && req.method !== 'HEAD') || + // Require Accept header + !req.headers || + typeof req.headers.accept !== 'string' || + // Ignore JSON requests + req.headers.accept.includes('application/json') || + // Require Accept: text/html or */* + !( + req.headers.accept.includes('text/html') || + req.headers.accept.includes('*/*') + ) + ) { + return next() + } + + const url = cleanUrl(req.url!) + const pathname = decodeURIComponent(url) + + // .html files are not handled by serveStaticMiddleware + // so we need to check if the file exists + if (pathname.endsWith('.html')) { + const filePath = path.join(root, pathname) + if (fs.existsSync(filePath)) { + debug?.(`Rewriting ${req.method} ${req.url} to ${url}`) + req.url = prepend + url + return next() + } + } + // trailing slash should check for fallback index.html + else if (pathname[pathname.length - 1] === '/') { + const filePath = path.join(root, pathname, 'index.html') + if (fs.existsSync(filePath)) { + const newUrl = url + 'index.html' + debug?.(`Rewriting ${req.method} ${req.url} to ${newUrl}`) + req.url = prepend + newUrl + return next() + } + } + // non-trailing slash should check for fallback .html + else { + const filePath = path.join(root, pathname + '.html') + if (fs.existsSync(filePath)) { + const newUrl = url + '.html' + debug?.(`Rewriting ${req.method} ${req.url} to ${newUrl}`) + req.url = prepend + newUrl + return next() + } + } + + if (spaFallback) { + debug?.(`Rewriting ${req.method} ${req.url} to /index.html`) + req.url = prepend + '/index.html' + } + + next() } } diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts index c25aaa3f02e3ee..874c94f84790fa 100644 --- a/packages/vite/src/node/server/middlewares/indexHtml.ts +++ b/packages/vite/src/node/server/middlewares/indexHtml.ts @@ -23,7 +23,7 @@ import { resolveHtmlTransforms, traverseHtml, } from '../../plugins/html' -import type { ResolvedConfig, ViteDevServer } from '../..' +import type { PreviewServer, ResolvedConfig, ViteDevServer } from '../..' import { send } from '../send' import { CLIENT_PUBLIC_PATH, FS_PREFIX } from '../../constants' import { @@ -32,6 +32,7 @@ import { fsPathFromId, getHash, injectQuery, + isDevServer, isJSRequest, joinUrlSegments, normalizePath, @@ -378,8 +379,14 @@ const devHtmlHook: IndexHtmlTransformHook = async ( } export function indexHtmlMiddleware( - server: ViteDevServer, + root: string, + server: ViteDevServer | PreviewServer, ): Connect.NextHandleFunction { + const isDev = isDevServer(server) + const headers = isDev + ? server.config.server.headers + : server.config.preview.headers + // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` return async function viteIndexHtmlMiddleware(req, res, next) { if (res.writableEnded) { @@ -389,14 +396,20 @@ export function indexHtmlMiddleware( const url = req.url && cleanUrl(req.url) // htmlFallbackMiddleware appends '.html' to URLs if (url?.endsWith('.html') && req.headers['sec-fetch-dest'] !== 'script') { - const filename = getHtmlFilename(url, server) - if (fs.existsSync(filename)) { + let filePath: string + if (isDev && url.startsWith(FS_PREFIX)) { + filePath = decodeURIComponent(fsPathFromId(url)) + } else { + filePath = path.join(root, decodeURIComponent(url)) + } + + if (fs.existsSync(filePath)) { try { - let html = await fsp.readFile(filename, 'utf-8') - html = await server.transformIndexHtml(url, html, req.originalUrl) - return send(req, res, html, 'html', { - headers: server.config.server.headers, - }) + let html = await fsp.readFile(filePath, 'utf-8') + if (isDev) { + html = await server.transformIndexHtml(url, html, req.originalUrl) + } + return send(req, res, html, 'html', { headers }) } catch (e) { return next(e) } diff --git a/packages/vite/src/node/server/middlewares/notFound.ts b/packages/vite/src/node/server/middlewares/notFound.ts new file mode 100644 index 00000000000000..4ecf6823dcaf89 --- /dev/null +++ b/packages/vite/src/node/server/middlewares/notFound.ts @@ -0,0 +1,9 @@ +import type { Connect } from 'dep-types/connect' + +export function notFoundMiddleware(): Connect.NextHandleFunction { + // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...` + return function vite404Middleware(_, res) { + res.statusCode = 404 + res.end() + } +} diff --git a/packages/vite/src/node/shortcuts.ts b/packages/vite/src/node/shortcuts.ts index 9b3671dbee8cf4..9a8dac1c457983 100644 --- a/packages/vite/src/node/shortcuts.ts +++ b/packages/vite/src/node/shortcuts.ts @@ -2,6 +2,7 @@ import readline from 'node:readline' import colors from 'picocolors' import { restartServerWithUrls } from './server' import type { ViteDevServer } from './server' +import { isDevServer } from './utils' import type { PreviewServer } from './preview' import { openBrowser } from './server/openBrowser' @@ -88,12 +89,6 @@ export function bindCLIShortcuts( server.httpServer.on('close', () => rl.close()) } -function isDevServer( - server: ViteDevServer | PreviewServer, -): server is ViteDevServer { - return 'pluginContainer' in server -} - const BASE_DEV_SHORTCUTS: CLIShortcut[] = [ { key: 'r', diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index dbd48ad43f5cc5..1e039d9beced7e 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -32,6 +32,7 @@ import { import type { DepOptimizationConfig } from './optimizer' import type { ResolvedConfig } from './config' import type { ResolvedServerUrls, ViteDevServer } from './server' +import type { PreviewServer } from './preview' import { type PackageCache, findNearestPackageData, @@ -1322,3 +1323,9 @@ export function getPackageManagerCommand( throw new TypeError(`Unknown command type: ${type}`) } } + +export function isDevServer( + server: ViteDevServer | PreviewServer, +): server is ViteDevServer { + return 'pluginContainer' in server +} diff --git a/packages/vite/src/types/shims.d.ts b/packages/vite/src/types/shims.d.ts index 03b1941201b17f..9f637b00e2b292 100644 --- a/packages/vite/src/types/shims.d.ts +++ b/packages/vite/src/types/shims.d.ts @@ -13,11 +13,6 @@ declare module 'http-proxy' { export = proxy } -declare module 'connect-history-api-fallback' { - const plugin: any - export = plugin -} - declare module 'launch-editor-middleware' { const plugin: any export = plugin diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index 498a1d380c6358..d3de2304894584 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -43,17 +43,13 @@ test('should get a 404 when using incorrect case', async () => { ) // fallback to index.html const iconPngResult = await fetchPath('ICON.png') - expect(iconPngResult.headers.get('Content-Type')).toBe( - isBuild ? 'text/html;charset=utf-8' : 'text/html', - ) + expect(iconPngResult.headers.get('Content-Type')).toBe('text/html') expect(iconPngResult.status).toBe(200) expect((await fetchPath('bar')).headers.get('Content-Type')).toBe('') // fallback to index.html const barResult = await fetchPath('BAR') - expect(barResult.headers.get('Content-Type')).toContain( - isBuild ? 'text/html;charset=utf-8' : 'text/html', - ) + expect(barResult.headers.get('Content-Type')).toContain('text/html') expect(barResult.status).toBe(200) }) diff --git a/playground/html/__tests__/html.spec.ts b/playground/html/__tests__/html.spec.ts index 879f9cb1edc0e7..01f0eca2e7e445 100644 --- a/playground/html/__tests__/html.spec.ts +++ b/playground/html/__tests__/html.spec.ts @@ -11,6 +11,12 @@ import { withRetry, } from '~utils' +function fetchHtml(p: string) { + return fetch(viteTestUrl + p, { + headers: { Accept: 'text/html,*/*' }, + }) +} + function testPage(isNested: boolean) { test('pre transform', async () => { expect(await page.$('head meta[name=viewport]')).toBeTruthy() @@ -355,3 +361,56 @@ describe.runIf(isServe)('warmup', () => { }) }) }) + +test('html serve behavior', async () => { + const [ + file, + fileSlash, + fileDotHtml, + + folder, + folderSlash, + folderSlashIndexHtml, + + both, + bothSlash, + bothDotHtml, + bothSlashIndexHtml, + ] = await Promise.all([ + fetchHtml('/serve/file'), // -> serve/file.html + fetchHtml('/serve/file/'), // -> index.html (404 in mpa) + fetchHtml('/serve/file.html'), // -> serve/file.html + + fetchHtml('/serve/folder'), // -> index.html (404 in mpa) + fetchHtml('/serve/folder/'), // -> serve/folder/index.html + fetchHtml('/serve/folder/index.html'), // -> serve/folder/index.html + + fetchHtml('/serve/both'), // -> serve/both.html + fetchHtml('/serve/both/'), // -> serve/both/index.html + fetchHtml('/serve/both.html'), // -> serve/both.html + fetchHtml('/serve/both/index.html'), // -> serve/both/index.html + ]) + + expect(file.status).toBe(200) + expect(await file.text()).toContain('file.html') + expect(fileSlash.status).toBe(200) + expect(await fileSlash.text()).toContain('index.html (fallback)') + expect(fileDotHtml.status).toBe(200) + expect(await fileDotHtml.text()).toContain('file.html') + + expect(folder.status).toBe(200) + expect(await folder.text()).toContain('index.html (fallback)') + expect(folderSlash.status).toBe(200) + expect(await folderSlash.text()).toContain('folder/index.html') + expect(folderSlashIndexHtml.status).toBe(200) + expect(await folderSlashIndexHtml.text()).toContain('folder/index.html') + + expect(both.status).toBe(200) + expect(await both.text()).toContain('both.html') + expect(bothSlash.status).toBe(200) + expect(await bothSlash.text()).toContain('both/index.html') + expect(bothDotHtml.status).toBe(200) + expect(await bothDotHtml.text()).toContain('both.html') + expect(bothSlashIndexHtml.status).toBe(200) + expect(await bothSlashIndexHtml.text()).toContain('both/index.html') +}) diff --git a/playground/html/index.html b/playground/html/index.html index 783cad93172f7a..829b362f433a9a 100644 --- a/playground/html/index.html +++ b/playground/html/index.html @@ -8,3 +8,4 @@

Hello

+

index.html (fallback)

diff --git a/playground/html/serve/both.html b/playground/html/serve/both.html new file mode 100644 index 00000000000000..9eebf466b653b5 --- /dev/null +++ b/playground/html/serve/both.html @@ -0,0 +1 @@ +

both.html

diff --git a/playground/html/serve/both/index.html b/playground/html/serve/both/index.html new file mode 100644 index 00000000000000..00a4791ad0a8b8 --- /dev/null +++ b/playground/html/serve/both/index.html @@ -0,0 +1 @@ +

both/index.html

diff --git a/playground/html/serve/file.html b/playground/html/serve/file.html new file mode 100644 index 00000000000000..f956e1216f1a1f --- /dev/null +++ b/playground/html/serve/file.html @@ -0,0 +1 @@ +

file.html

diff --git a/playground/html/serve/folder/index.html b/playground/html/serve/folder/index.html new file mode 100644 index 00000000000000..d66d0959648da4 --- /dev/null +++ b/playground/html/serve/folder/index.html @@ -0,0 +1 @@ +

folder/index.html

diff --git a/playground/html/vite.config.js b/playground/html/vite.config.js index 4edc6f12abcbf3..6bcfebdb677f92 100644 --- a/playground/html/vite.config.js +++ b/playground/html/vite.config.js @@ -30,6 +30,10 @@ export default defineConfig({ env: resolve(__dirname, 'env.html'), sideEffects: resolve(__dirname, 'side-effects/index.html'), 'a á': resolve(__dirname, 'a á.html'), + serveFile: resolve(__dirname, 'serve/file.html'), + serveFolder: resolve(__dirname, 'serve/folder/index.html'), + serveBothFile: resolve(__dirname, 'serve/both.html'), + serveBothFolder: resolve(__dirname, 'serve/both/index.html'), }, }, }, diff --git a/playground/legacy/__tests__/legacy.spec.ts b/playground/legacy/__tests__/legacy.spec.ts index f71665c4939aeb..405c61f47e2700 100644 --- a/playground/legacy/__tests__/legacy.spec.ts +++ b/playground/legacy/__tests__/legacy.spec.ts @@ -52,13 +52,13 @@ test('generates assets', async () => { () => page.textContent('#assets'), isBuild ? [ - 'index: text/html;charset=utf-8', - 'index-legacy: text/html;charset=utf-8', - 'chunk-async: text/html;charset=utf-8', - 'chunk-async-legacy: text/html;charset=utf-8', + 'index: text/html', + 'index-legacy: text/html', + 'chunk-async: text/html', + 'chunk-async-legacy: text/html', 'immutable-chunk: application/javascript', 'immutable-chunk-legacy: application/javascript', - 'polyfills-legacy: text/html;charset=utf-8', + 'polyfills-legacy: text/html', ].join('\n') : [ 'index: text/html', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dae840203fe7fa..3987537ee49d5b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -285,9 +285,6 @@ importers: connect: specifier: ^3.7.0 version: 3.7.0 - connect-history-api-fallback: - specifier: ^2.0.0 - version: 2.0.0 convert-source-map: specifier: ^2.0.0 version: 2.0.0 @@ -5002,11 +4999,6 @@ packages: /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - /connect-history-api-fallback@2.0.0: - resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} - engines: {node: '>=0.8'} - dev: true - /connect@3.7.0: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} From 72340211d3eedf0ffd12618622d6b8cdc4c133d0 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Tue, 31 Oct 2023 00:58:27 +0800 Subject: [PATCH 09/11] refactor(esbuild)!: remove esbuild 0.17 -> 0.18 compat (#14804) --- docs/guide/features.md | 25 ++++++++++++++++ docs/guide/migration.md | 25 ++++++++++++++++ .../node/__tests__/plugins/esbuild.spec.ts | 15 ---------- packages/vite/src/node/optimizer/index.ts | 12 ++------ packages/vite/src/node/optimizer/scan.ts | 30 ++----------------- packages/vite/src/node/plugins/esbuild.ts | 30 ++++--------------- .../__tests__/tsconfig-json.spec.ts | 5 ++-- playground/tsconfig-json/tsconfig.json | 3 +- 8 files changed, 65 insertions(+), 80 deletions(-) diff --git a/docs/guide/features.md b/docs/guide/features.md index 6044aa99592765..6b195cd5ec41cb 100644 --- a/docs/guide/features.md +++ b/docs/guide/features.md @@ -57,6 +57,8 @@ Some configuration fields under `compilerOptions` in `tsconfig.json` require spe #### `isolatedModules` +- [TypeScript documentation](https://www.typescriptlang.org/tsconfig#isolatedModules) + Should be set to `true`. It is because `esbuild` only performs transpilation without type information, it doesn't support certain features like const enum and implicit type-only imports. @@ -67,8 +69,12 @@ However, some libraries (e.g. [`vue`](https://github.com/vuejs/core/issues/1228) #### `useDefineForClassFields` +- [TypeScript documentation](https://www.typescriptlang.org/tsconfig#useDefineForClassFields) + Starting from Vite 2.5.0, the default value will be `true` if the TypeScript target is `ESNext` or `ES2022` or newer. It is consistent with the [behavior of `tsc` 4.3.2 and later](https://github.com/microsoft/TypeScript/pull/42663). It is also the standard ECMAScript runtime behavior. +Other TypeScript targets will default to `false`. + But it may be counter-intuitive for those coming from other programming languages or older versions of TypeScript. You can read more about the transition in the [TypeScript 3.7 release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#the-usedefineforclassfields-flag-and-the-declare-property-modifier). @@ -78,13 +84,32 @@ Most libraries expect `"useDefineForClassFields": true`, such as [MobX](https:// But a few libraries haven't transitioned to this new default yet, including [`lit-element`](https://github.com/lit/lit-element/issues/1030). Please explicitly set `useDefineForClassFields` to `false` in these cases. +#### `target` + +- [TypeScript documentation](https://www.typescriptlang.org/tsconfig#target) + +Vite does not transpile TypeScript with the configured `target` value by default, following the same behaviour as `esbuild`. + +The [`esbuild.target`](/config/shared-options.html#esbuild) option can be used instead, which defaults to `esnext` for minimal transpilation. In builds, the [`build.target`](/config/build-options.html#build-target) option takes higher priority and can also be set if needed. + +::: warning `useDefineForClassFields` +If `target` is not `ESNext` or `ES2022` or newer, or if there's no `tsconfig.json` file, `useDefineForClassFields` will default to `false` which can be problematic with the default `esbuild.target` value of `esnext`. It may transpile to [static initialization blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks#browser_compatibility) which may not be supported in your browser. + +As such, it is recommended to set `target` to `ESNext` or `ES2022` or newer, or set `useDefineForClassFields` to `true` explicitly when configuring `tsconfig.json`. +::: + #### Other Compiler Options Affecting the Build Result - [`extends`](https://www.typescriptlang.org/tsconfig#extends) - [`importsNotUsedAsValues`](https://www.typescriptlang.org/tsconfig#importsNotUsedAsValues) - [`preserveValueImports`](https://www.typescriptlang.org/tsconfig#preserveValueImports) +- [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax) +- [`jsx`](https://www.typescriptlang.org/tsconfig#jsx) - [`jsxFactory`](https://www.typescriptlang.org/tsconfig#jsxFactory) - [`jsxFragmentFactory`](https://www.typescriptlang.org/tsconfig#jsxFragmentFactory) +- [`jsxImportSource`](https://www.typescriptlang.org/tsconfig#jsxImportSource) +- [`experimentalDecorators`](https://www.typescriptlang.org/tsconfig#experimentalDecorators) +- [`alwaysStrict`](https://www.typescriptlang.org/tsconfig#alwaysStrict) If migrating your codebase to `"isolatedModules": true` is an insurmountable effort, you may be able to get around it with a third-party plugin such as [rollup-plugin-friendly-type-imports](https://www.npmjs.com/package/rollup-plugin-friendly-type-imports). However, this approach is not officially supported by Vite. diff --git a/docs/guide/migration.md b/docs/guide/migration.md index 16f63bdceb2e57..b04e2ac72aaefc 100644 --- a/docs/guide/migration.md +++ b/docs/guide/migration.md @@ -136,6 +136,31 @@ CLI shortcuts, like `r` to restart the dev server, now require an additional `En This change prevents Vite from swallowing and controlling OS-specific shortcuts, allowing better compatibility when combining the Vite dev server with other processes, and avoids the [previous caveats](https://github.com/vitejs/vite/pull/14342). +### Update `experimentalDecorators` and `useDefineForClassFields` TypeScript behaviour + +Vite 5 uses esbuild 0.19 and removes the compatibility layer for esbuild 0.18, which changes how `experimentalDecorators` and `useDefineForClassFields` are handled. + +- **`experimentalDecorators` is not enabled by default** + + You need to set `compilerOptions.experimentalDecorators` to `true` in `tsconfig.json` to use decorators. + +- **`useDefineForClassFields` defaults depend on the TypeScript `target` value** + + If `target` is not `ESNext` or `ES2022` or newer, or if there's no `tsconfig.json` file, `useDefineForClassFields` will default to `false` which can be problematic with the default `esbuild.target` value of `esnext`. It may transpile to [static initialization blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks#browser_compatibility) which may not be supported in your browser. + + As such, it is recommended to set `target` to `ESNext` or `ES2022` or newer, or set `useDefineForClassFields` to `true` explicitly when configuring `tsconfig.json`. + +```jsonc +{ + "compilerOptions": { + // Set true if you use decorators + "experimentalDecorators": true, + // Set true if you see parsing errors in your browser + "useDefineForClassFields": true + } +} +``` + ### Remove `--https` flag and `https: true` `--https` flag sets `https: true`. This config was meant to be used together with the automatic https certification generation feature which [was dropped in Vite 3](https://v3.vitejs.dev/guide/migration.html#automatic-https-certificate-generation). This config no longer makes sense as it will make Vite start a HTTPS server without a certificate. diff --git a/packages/vite/src/node/__tests__/plugins/esbuild.spec.ts b/packages/vite/src/node/__tests__/plugins/esbuild.spec.ts index 0d6d81af898e5a..8992000da101a5 100644 --- a/packages/vite/src/node/__tests__/plugins/esbuild.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/esbuild.spec.ts @@ -383,21 +383,6 @@ describe('transformWithEsbuild', () => { const actual = await transformClassCode('es2022', {}) expect(actual).toBe(defineForClassFieldsFalseTransformedCode) }) - - test('useDefineForClassFields: false and static property should not be transpile to static block', async () => { - const result = await transformWithEsbuild( - ` - class foo { - static bar = 'bar' - } - `, - 'bar.ts', - { - target: 'esnext', - }, - ) - expect(result?.code).not.toContain('static {') - }) }) }) diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 986a748e055705..edc516000fa57c 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -27,7 +27,7 @@ import { import { transformWithEsbuild } from '../plugins/esbuild' import { ESBUILD_MODULES_TARGET } from '../constants' import { esbuildCjsExternalPlugin, esbuildDepPlugin } from './esbuildDepPlugin' -import { resolveTsconfigRaw, scanImports } from './scan' +import { scanImports } from './scan' import { createOptimizeDepsIncludeResolver, expandGlobIds } from './resolve' export { initDepsOptimizer, @@ -730,12 +730,8 @@ async function prepareEsbuildOptimizerRun( const optimizeDeps = getDepOptimizationConfig(config, ssr) - const { - plugins: pluginsFromConfig = [], - tsconfig, - tsconfigRaw, - ...esbuildOptions - } = optimizeDeps?.esbuildOptions ?? {} + const { plugins: pluginsFromConfig = [], ...esbuildOptions } = + optimizeDeps?.esbuildOptions ?? {} await Promise.all( Object.keys(depsInfo).map(async (id) => { @@ -826,8 +822,6 @@ async function prepareEsbuildOptimizerRun( metafile: true, plugins, charset: 'utf8', - tsconfig, - tsconfigRaw: resolveTsconfigRaw(tsconfig, tsconfigRaw), ...esbuildOptions, supported: { 'dynamic-import': true, diff --git a/packages/vite/src/node/optimizer/scan.ts b/packages/vite/src/node/optimizer/scan.ts index 9f4ceb28701e9f..c0d97f480ca9de 100644 --- a/packages/vite/src/node/optimizer/scan.ts +++ b/packages/vite/src/node/optimizer/scan.ts @@ -5,7 +5,6 @@ import { performance } from 'node:perf_hooks' import glob from 'fast-glob' import type { BuildContext, - BuildOptions, Loader, OnLoadArgs, OnLoadResult, @@ -214,12 +213,8 @@ async function prepareEsbuildScanner( const plugin = esbuildScanPlugin(config, container, deps, missing, entries) - const { - plugins = [], - tsconfig, - tsconfigRaw, - ...esbuildOptions - } = config.optimizeDeps?.esbuildOptions ?? {} + const { plugins = [], ...esbuildOptions } = + config.optimizeDeps?.esbuildOptions ?? {} return await esbuild.context({ absWorkingDir: process.cwd(), @@ -232,8 +227,6 @@ async function prepareEsbuildScanner( format: 'esm', logLevel: 'silent', plugins: [...plugins, plugin], - tsconfig, - tsconfigRaw: resolveTsconfigRaw(tsconfig, tsconfigRaw), ...esbuildOptions, }) } @@ -684,22 +677,3 @@ function isScannable(id: string, extensions: string[] | undefined): boolean { false ) } - -// esbuild v0.18 only transforms decorators when `experimentalDecorators` is set to `true`. -// To preserve compat with the esbuild breaking change, we set `experimentalDecorators` to -// `true` by default if it's unset. -// TODO: Remove this in Vite 5 and check https://github.com/vitejs/vite/pull/13805#issuecomment-1633612320 -export function resolveTsconfigRaw( - tsconfig: string | undefined, - tsconfigRaw: BuildOptions['tsconfigRaw'], -): BuildOptions['tsconfigRaw'] { - return tsconfig || typeof tsconfigRaw === 'string' - ? tsconfigRaw - : { - ...tsconfigRaw, - compilerOptions: { - experimentalDecorators: true, - ...tsconfigRaw?.compilerOptions, - }, - } -} diff --git a/packages/vite/src/node/plugins/esbuild.ts b/packages/vite/src/node/plugins/esbuild.ts index 3a0e1eb7616d1b..ba7f338c8eec59 100644 --- a/packages/vite/src/node/plugins/esbuild.ts +++ b/packages/vite/src/node/plugins/esbuild.ts @@ -93,7 +93,6 @@ export async function transformWithEsbuild( } let tsconfigRaw = options?.tsconfigRaw - const fallbackSupported: Record = {} // if options provide tsconfigRaw in string, it takes highest precedence if (typeof tsconfigRaw !== 'string') { @@ -140,23 +139,6 @@ export async function transformWithEsbuild( compilerOptions.useDefineForClassFields = false } - // esbuild v0.18 only transforms decorators when `experimentalDecorators` is set to `true`. - // To preserve compat with the esbuild breaking change, we set `experimentalDecorators` to - // `true` by default if it's unset. - // TODO: Remove this in Vite 5 - if (compilerOptions.experimentalDecorators === undefined) { - compilerOptions.experimentalDecorators = true - } - - // Compat with esbuild 0.17 where static properties are transpiled to - // static blocks when `useDefineForClassFields` is false. Its support - // is not great yet, so temporarily disable it for now. - // TODO: Remove this in Vite 5, don't pass hardcoded `esnext` target - // to `transformWithEsbuild` in the esbuild plugin. - if (compilerOptions.useDefineForClassFields !== true) { - fallbackSupported['class-static-blocks'] = false - } - // esbuild uses tsconfig fields when both the normal options and tsconfig was set // but we want to prioritize the normal options if (options) { @@ -179,10 +161,6 @@ export async function transformWithEsbuild( ...options, loader, tsconfigRaw, - supported: { - ...fallbackSupported, - ...options?.supported, - }, } // Some projects in the ecosystem are calling this function with an ESBuildOptions @@ -220,9 +198,13 @@ export async function transformWithEsbuild( if (e.errors) { e.frame = '' e.errors.forEach((m: Message) => { - if (m.text === 'Experimental decorators are not currently enabled') { + if ( + m.text === 'Experimental decorators are not currently enabled' || + m.text === + 'Parameter decorators only work when experimental decorators are enabled' + ) { m.text += - '. Vite 4.4+ now uses esbuild 0.18 and you need to enable them by adding "experimentalDecorators": true in your "tsconfig.json" file.' + '. Vite 5 now uses esbuild 0.18 and you need to enable them by adding "experimentalDecorators": true in your "tsconfig.json" file.' } e.frame += `\n` + prettifyMessage(m, code) }) diff --git a/playground/tsconfig-json/__tests__/tsconfig-json.spec.ts b/playground/tsconfig-json/__tests__/tsconfig-json.spec.ts index dd130a65291001..4ecdff687fbaa2 100644 --- a/playground/tsconfig-json/__tests__/tsconfig-json.spec.ts +++ b/playground/tsconfig-json/__tests__/tsconfig-json.spec.ts @@ -71,9 +71,8 @@ describe('transformWithEsbuild', () => { test('experimentalDecorators', async () => { const main = path.resolve(__dirname, '../src/decorator.ts') const mainContent = fs.readFileSync(main, 'utf-8') - // Should not error when transpiling decorators - // TODO: In Vite 5, this should require setting `tsconfigRaw.experimentalDecorators` - // or via the closest `tsconfig.json` + // Should not error when transpiling decorators as nearest tsconfig.json + // has "experimentalDecorators": true const result = await transformWithEsbuild(mainContent, main, { target: 'es2020', }) diff --git a/playground/tsconfig-json/tsconfig.json b/playground/tsconfig-json/tsconfig.json index f15aff13b3bc35..6445b1652ea0e1 100644 --- a/playground/tsconfig-json/tsconfig.json +++ b/playground/tsconfig-json/tsconfig.json @@ -14,7 +14,8 @@ "noImplicitReturns": true, "useDefineForClassFields": true, - "importsNotUsedAsValues": "preserve" + "importsNotUsedAsValues": "preserve", + "experimentalDecorators": true }, "include": ["./src"] } From 8db40ee5de67047e7f31a4d0cd27c6e86c91449c Mon Sep 17 00:00:00 2001 From: ihch Date: Tue, 31 Oct 2023 02:17:20 +0900 Subject: [PATCH 10/11] fix(worker): force rollup to build workerImportMetaUrl under watch mode (#14712) --- packages/vite/src/node/plugins/worker.ts | 2 +- .../src/node/plugins/workerImportMetaUrl.ts | 24 ++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/vite/src/node/plugins/worker.ts b/packages/vite/src/node/plugins/worker.ts index b4f26f83355552..0df6f9d843e99c 100644 --- a/packages/vite/src/node/plugins/worker.ts +++ b/packages/vite/src/node/plugins/worker.ts @@ -218,7 +218,7 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin { }, shouldTransformCachedModule({ id }) { - if (isBuild && isWorkerQueryId(id) && config.build.watch) { + if (isBuild && config.build.watch && isWorkerQueryId(id)) { return true } }, diff --git a/packages/vite/src/node/plugins/workerImportMetaUrl.ts b/packages/vite/src/node/plugins/workerImportMetaUrl.ts index 85ec7c5b57240e..e88d1ac3362a43 100644 --- a/packages/vite/src/node/plugins/workerImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/workerImportMetaUrl.ts @@ -96,6 +96,17 @@ function getWorkerType(raw: string, clean: string, i: number): WorkerType { return 'classic' } +function isIncludeWorkerImportMetaUrl(code: string): boolean { + if ( + (code.includes('new Worker') || code.includes('new SharedWorker')) && + code.includes('new URL') && + code.includes(`import.meta.url`) + ) { + return true + } + return false +} + export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin { const isBuild = config.command === 'build' let workerResolver: ResolveFn @@ -113,14 +124,15 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin { return { name: 'vite:worker-import-meta-url', + shouldTransformCachedModule({ code }) { + if (isBuild && config.build.watch && isIncludeWorkerImportMetaUrl(code)) { + return true + } + }, + async transform(code, id, options) { const ssr = options?.ssr === true - if ( - !options?.ssr && - (code.includes('new Worker') || code.includes('new SharedWorker')) && - code.includes('new URL') && - code.includes(`import.meta.url`) - ) { + if (!options?.ssr && isIncludeWorkerImportMetaUrl(code)) { const query = parseRequest(id) let s: MagicString | undefined const cleanString = stripLiteral(code) From 2124264ceebce83d94116aa53f6db9bed5e8af4b Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 31 Oct 2023 01:25:38 +0800 Subject: [PATCH 11/11] release: v5.0.0-beta.14 --- packages/vite/CHANGELOG.md | 14 ++++++++++++++ packages/vite/package.json | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/vite/CHANGELOG.md b/packages/vite/CHANGELOG.md index b347bef79d7bf4..d9046ab3e84b26 100644 --- a/packages/vite/CHANGELOG.md +++ b/packages/vite/CHANGELOG.md @@ -1,3 +1,17 @@ +## 5.0.0-beta.14 (2023-10-30) + +* fix(define): correctly replace same define values (#14786) ([f36fcd2](https://github.com/vitejs/vite/commit/f36fcd2)), closes [#14786](https://github.com/vitejs/vite/issues/14786) +* fix(deps): update all non-major dependencies (#14729) ([d5d96e7](https://github.com/vitejs/vite/commit/d5d96e7)), closes [#14729](https://github.com/vitejs/vite/issues/14729) +* fix(worker): force rollup to build workerImportMetaUrl under watch mode (#14712) ([8db40ee](https://github.com/vitejs/vite/commit/8db40ee)), closes [#14712](https://github.com/vitejs/vite/issues/14712) +* fix(html)!: align html serving between dev and preview (#14756) ([4f71ae8](https://github.com/vitejs/vite/commit/4f71ae8)), closes [#14756](https://github.com/vitejs/vite/issues/14756) +* refactor!: remove non boolean middleware mode (#14792) ([deb5515](https://github.com/vitejs/vite/commit/deb5515)), closes [#14792](https://github.com/vitejs/vite/issues/14792) +* refactor(esbuild)!: remove esbuild 0.17 -> 0.18 compat (#14804) ([7234021](https://github.com/vitejs/vite/commit/7234021)), closes [#14804](https://github.com/vitejs/vite/issues/14804) +* chore: update license (#14790) ([ac5d8a7](https://github.com/vitejs/vite/commit/ac5d8a7)), closes [#14790](https://github.com/vitejs/vite/issues/14790) +* chore(shortcuts): resolve generic type error (#14802) ([a090742](https://github.com/vitejs/vite/commit/a090742)), closes [#14802](https://github.com/vitejs/vite/issues/14802) +* feat: add a runtime warning for the old object type transformIndexHtml hook (#14791) ([17fb5ee](https://github.com/vitejs/vite/commit/17fb5ee)), closes [#14791](https://github.com/vitejs/vite/issues/14791) + + + ## 5.0.0-beta.13 (2023-10-27) * fix: skip watchPackageDataPlugin for worker builds (#14762) ([9babef5](https://github.com/vitejs/vite/commit/9babef5)), closes [#14762](https://github.com/vitejs/vite/issues/14762) diff --git a/packages/vite/package.json b/packages/vite/package.json index 831a138585f27f..01171876960274 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -1,6 +1,6 @@ { "name": "vite", - "version": "5.0.0-beta.13", + "version": "5.0.0-beta.14", "type": "module", "license": "MIT", "author": "Evan You",