From 532e2ed340673f92f767d66538eef40e38dc6c8a Mon Sep 17 00:00:00 2001 From: Ludovico Fischer Date: Fri, 2 Apr 2021 23:12:56 +0200 Subject: [PATCH] feat: upgrade esbuild and remove dynamic import polyfill BREAKING CHANGE: update modules target to avoid mixing `import` and `require()` BREAKING CHANGE: remove dynamic import polyfill docs: update browser support docs --- docs/config/index.md | 15 -- docs/guide/backend-integration.md | 7 - docs/guide/build.md | 11 +- docs/guide/comparisons.md | 1 - docs/guide/features.md | 6 - docs/guide/index.md | 4 +- packages/vite/package.json | 2 +- packages/vite/src/node/build.ts | 27 ++-- packages/vite/src/node/config.ts | 19 +++ .../src/node/plugins/dynamicImportPolyfill.ts | 145 +----------------- packages/vite/src/node/plugins/html.ts | 7 - .../src/node/plugins/importAnalysisBuild.ts | 8 +- packages/vite/src/node/plugins/index.ts | 4 - scripts/jestPerTestSetup.ts | 3 +- yarn.lock | 8 +- 15 files changed, 50 insertions(+), 217 deletions(-) diff --git a/docs/config/index.md b/docs/config/index.md index 10716e71ef3736..f707f72def12c1 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -447,21 +447,6 @@ export default async ({ command, mode }) => { Note the build will fail if the code contains features that cannot be safely transpiled by esbuild. See [esbuild docs](https://esbuild.github.io/content-types/#javascript) for more details. -### build.polyfillDynamicImport - -- **Type:** `boolean` -- **Default:** `true` unless `build.target` is `'esnext'` - - Whether to automatically inject [dynamic import polyfill](https://github.com/GoogleChromeLabs/dynamic-import-polyfill). - - The polyfill is auto injected into the proxy module of each `index.html` entry. If the build is configured to use a non-html custom entry via `build.rollupOptions.input`, then it is necessary to manually import the polyfill in your custom entry: - - ```js - import 'vite/dynamic-import-polyfill' - ``` - - Note: the polyfill does **not** apply to [Library Mode](/guide/build#library-mode). If you need to support browsers without native dynamic import, you should probably avoid using it in your library. - ### build.outDir - **Type:** `string` diff --git a/docs/guide/backend-integration.md b/docs/guide/backend-integration.md index 4669bd6c818dec..fad9fff75c61d6 100644 --- a/docs/guide/backend-integration.md +++ b/docs/guide/backend-integration.md @@ -20,13 +20,6 @@ Or you can follow these steps to configure it manually: } ``` - Also remember to add the [dynamic import polyfill](/config/#build-polyfilldynamicimport) to your entry, since it will no longer be auto-injected: - - ```js - // add the beginning of your app entry - import 'vite/dynamic-import-polyfill' - ``` - 2. For development, inject the following in your server's HTML template (substitute `http://localhost:3000` with the local URL Vite is running at): ```html diff --git a/docs/guide/build.md b/docs/guide/build.md index 5c6f45c46eb1b1..7dd46ab435b9fa 100644 --- a/docs/guide/build.md +++ b/docs/guide/build.md @@ -4,14 +4,11 @@ When it is time to deploy your app for production, simply run the `vite build` c ## Browser Compatibility -The production bundle assumes a baseline support for modern JavaScript. By default, all code is transpiled targeting [browsers with native ESM script tag support](https://caniuse.com/es6-module): +The production bundle assumes support for modern JavaScript. By default, vite targets browsers which support the [native ESM script tag](https://caniuse.com/es6-module) and [native ESM dynamic import](https://caniuse.com/es6-module-dynamic-import). As a reference, vite uses this [browserslist](https://github.com/browserslist/browserslist) query: -- Chrome >=61 -- Firefox >=60 -- Safari >=11 -- Edge >=16 - -A lightweight [dynamic import polyfill](https://github.com/GoogleChromeLabs/dynamic-import-polyfill) is also automatically injected. +``` +defaults and supports es6-module and supports es6-module-dynamic-import, not opera > 0, not samsung > 0, not and_qq > 0 +``` You can specify custom targets via the [`build.target` config option](/config/#build-target), where the lowest target is `es2015`. diff --git a/docs/guide/comparisons.md b/docs/guide/comparisons.md index 3e944d9b23aba5..1e849f88a71a68 100644 --- a/docs/guide/comparisons.md +++ b/docs/guide/comparisons.md @@ -16,7 +16,6 @@ Due to a more integrated build process, Vite supports a wide range of features t - [Library Mode](./build#library-mode) - [Automatic CSS code-splitting](./features#css-code-splitting) - [Optimized async chunk loading](./features#async-chunk-loading-optimization) -- [Automatic dynamic import polyfill](./features#dynamic-import-polyfill) - Official [legacy mode plugin](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) that generates dual modern/legacy bundles and auto delivers the right bundle based on browser support. **Faster Dependency Pre-Bundling** diff --git a/docs/guide/features.md b/docs/guide/features.md index b9b343bad1ad1b..e30ba02f48ddf9 100644 --- a/docs/guide/features.md +++ b/docs/guide/features.md @@ -304,12 +304,6 @@ import MyWorker from './worker?worker&inline' > Features listed below are automatically applied as part of the build process and there is no need for explicit configuration unless you want to disable them. -### Dynamic Import Polyfill - -Vite uses ES dynamic import as code-splitting points. The generated code will also use dynamic imports to load the async chunks. However, native ESM dynamic imports support landed later than ESM via script tags and there is a browser support discrepancy between the two features. Vite automatically injects a light-weight [dynamic import polyfill](https://github.com/GoogleChromeLabs/dynamic-import-polyfill) to ease out that difference. - -If you know you are only targeting browsers with native dynamic import support, you can explicitly disable this feature via [`build.polyfillDynamicImport`](/config/#build-polyfilldynamicimport). - ### CSS Code Splitting Vite automatically extracts the CSS used by modules in an async chunk and generate a separate file for it. The CSS file is automatically loaded via a `` tag when the associated async chunk is loaded, and the async chunk is guaranteed to only be evaluated after the CSS is loaded to avoid [FOUC](https://en.wikipedia.org/wiki/Flash_of_unstyled_content#:~:text=A%20flash%20of%20unstyled%20content,before%20all%20information%20is%20retrieved.). diff --git a/docs/guide/index.md b/docs/guide/index.md index 431713e63dc741..9d568551f776dd 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -14,9 +14,7 @@ You can learn more about the rationale behind the project in the [Why Vite](./wh ## Browser Support -- For development: [native ESM dynamic import support](https://caniuse.com/es6-module-dynamic-import) is required. - -- For production: the default build targets browsers that support [native ESM via script tags](https://caniuse.com/es6-module). Legacy browsers can be supported via the official [@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) - see the [Building for Production](./build) section for more details. +- The default build targets browsers that support both [native ESM via script tags](https://caniuse.com/es6-module) and [native ESM dynamic import](https://caniuse.com/es6-module-dynamic-import). Legacy browsers can be supported via the official [@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) - see the [Building for Production](./build) section for more details. ## Scaffolding Your First Vite Project diff --git a/packages/vite/package.json b/packages/vite/package.json index 2bbbea8812a665..4cd54737e678c9 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -46,7 +46,7 @@ }, "//": "READ .github/contributing.md to understand what to put under deps vs. devDeps!", "dependencies": { - "esbuild": "^0.9.3", + "esbuild": "^0.11.18", "postcss": "^8.2.1", "resolve": "^1.19.0", "rollup": "^2.38.5" diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 825e627b06fbb9..431294ff6a7dff 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -51,9 +51,8 @@ export interface BuildOptions { * import) * * Default: 'modules' - Similar to `@babel/preset-env`'s targets.esmodules, - * transpile targeting browsers that natively support es module imports. Also - * injects a light-weight dynamic import polyfill. - * https://caniuse.com/es6-module + * transpile targeting browsers that natively support dynamic es module imports. + * https://caniuse.com/es6-module-dynamic-import * * Another special value is 'esnext' - which only performs minimal transpiling * (for minification compat) and assumes native dynamic imports support. @@ -63,9 +62,9 @@ export interface BuildOptions { */ target?: 'modules' | TransformOptions['target'] | false /** - * Whether to inject dynamic import polyfill. Defaults to `true`, unless - * `target` is `'esnext'`. + * whether to inject dynamic import polyfill. * Note: does not apply to library mode. + * @deprecated the dynamic import polyfill has been removed */ polyfillDynamicImport?: boolean /** @@ -195,12 +194,13 @@ export interface LibraryOptions { export type LibraryFormats = 'es' | 'cjs' | 'umd' | 'iife' -export type ResolvedBuildOptions = Required> +export type ResolvedBuildOptions = Required< + Omit +> export function resolveBuildOptions(raw?: BuildOptions): ResolvedBuildOptions { const resolved: ResolvedBuildOptions = { target: 'modules', - polyfillDynamicImport: raw?.target !== 'esnext' && !raw?.lib, outDir: 'dist', assetsDir: 'assets', assetsInlineLimit: 4096, @@ -229,10 +229,15 @@ export function resolveBuildOptions(raw?: BuildOptions): ResolvedBuildOptions { // handle special build targets if (resolved.target === 'modules') { - // https://caniuse.com/es6-module - // edge18 according to js-table (destructuring is not supported in edge16) - // https://github.com/evanw/esbuild/blob/d943e89e50696647d6c89ae623ddfdf564ad3cfc/internal/compat/js_table.go#L84 - resolved.target = ['es2019', 'edge18', 'firefox60', 'chrome61', 'safari11'] + // Support browserslist + // "defaults and supports es6-module and supports es6-module-dynamic-import", + resolved.target = [ + 'es2019', + 'edge88', + 'firefox78', + 'chrome87', + 'safari13.1' + ] } else if (resolved.target === 'esnext' && resolved.minify !== 'esbuild') { // esnext + terser: limit to es2019 so it can be minified by terser resolved.target = 'es2019' diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 10f8919952d04a..6d3fde45f6eeb3 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -447,6 +447,25 @@ export async function resolveConfig( } }) + if (config.build?.polyfillDynamicImport) { + logDeprecationWarning( + 'build.polyfillDynamicImport', + '"polyfillDynamicImport" has been removed. Please use @vitejs/plugin-legacy if your target browsers do not support dynamic imports.' + ) + } + + Object.defineProperty(resolvedBuildOptions, 'polyfillDynamicImport', { + enumerable: false, + get() { + logDeprecationWarning( + 'build.polyfillDynamicImport', + '"polyfillDynamicImport" has been removed. Please use @vitejs/plugin-legacy if your target browsers do not support dynamic imports.', + new Error() + ) + return false + } + }) + if (config.alias) { logDeprecationWarning('alias', 'Use "resolve.alias" instead.') } diff --git a/packages/vite/src/node/plugins/dynamicImportPolyfill.ts b/packages/vite/src/node/plugins/dynamicImportPolyfill.ts index 8561af6968c8b0..7d2cac4cc9d452 100644 --- a/packages/vite/src/node/plugins/dynamicImportPolyfill.ts +++ b/packages/vite/src/node/plugins/dynamicImportPolyfill.ts @@ -1,142 +1,3 @@ -import { ResolvedConfig } from '..' -import { Plugin } from '../plugin' -import { isModernFlag } from './importAnalysisBuild' -import path from 'path' - -export const polyfillId = 'vite/dynamic-import-polyfill' - -function resolveModulePath(config: ResolvedConfig) { - const { - base, - build: { assetsDir } - } = config - // #2918 path.posix.join returns a wrong path when config.base is a URL - if (/^(https?:)?(\/\/)/i.test(base)) { - return `${base.replace(/\/$/, '')}/${assetsDir}/` - } - return path.posix.join(base, assetsDir, '/') -} - -export function dynamicImportPolyfillPlugin(config: ResolvedConfig): Plugin { - const skip = config.command === 'serve' || config.build.ssr - let polyfillLoaded = false - const polyfillString = - `const p = ${polyfill.toString()};` + - `${isModernFlag}&&p(${JSON.stringify(resolveModulePath(config))});` - - return { - name: 'vite:dynamic-import-polyfill', - resolveId(id) { - if (id === polyfillId) { - return id - } - }, - load(id) { - if (id === polyfillId) { - if (skip) { - return '' - } - polyfillLoaded = true - // return a placeholder here and defer the injection to renderChunk - // so that we can selectively skip the injection based on output format - return polyfillString - } - }, - - renderDynamicImport({ format }) { - if (skip || format !== 'es') { - return null - } - if (!polyfillLoaded) { - throw new Error( - `Vite's dynamic import polyfill is enabled but was never imported. This ` + - `should only happen when using custom non-html rollup inputs. Make ` + - `sure to add \`import "${polyfillId}"\` as the first statement in ` + - `your custom entry.` - ) - } - // we do not actually return anything here because rewriting here would - // make it impossible to use es-module-lexer on the rendered chunks, which - // we need for import graph optimization in ./importAnalysisBuild. - } - } -} - -/** -The following polyfill function is meant to run in the browser and adapted from -https://github.com/GoogleChromeLabs/dynamic-import-polyfill - -MIT License - -Copyright (c) 2018 uupaa and 2019 Google LLC - -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 -*/ - -declare const self: any -declare const location: any -declare const document: any -declare const URL: any -declare const Blob: any - -function polyfill(modulePath = '.', importFunctionName = '__import__') { - try { - self[importFunctionName] = new Function('u', `return import(u)`) - } catch (error) { - const baseURL = new URL(modulePath, location) - const cleanup = (script: any) => { - URL.revokeObjectURL(script.src) - script.remove() - } - - self[importFunctionName] = (url: string) => - new Promise((resolve, reject) => { - const absURL = new URL(url, baseURL) - - // If the module has already been imported, resolve immediately. - if (self[importFunctionName].moduleMap[absURL]) { - return resolve(self[importFunctionName].moduleMap[absURL]) - } - - const moduleBlob = new Blob( - [ - `import * as m from '${absURL}';`, - `${importFunctionName}.moduleMap['${absURL}']=m;` - ], - { type: 'text/javascript' } - ) - - const script = Object.assign(document.createElement('script'), { - type: 'module', - src: URL.createObjectURL(moduleBlob), - onerror() { - reject(new Error(`Failed to import: ${url}`)) - cleanup(script) - }, - onload() { - resolve(self[importFunctionName].moduleMap[absURL]) - cleanup(script) - } - }) - - document.head.appendChild(script) - }) - - self[importFunctionName].moduleMap = {} - } -} +throw new Error( + `Vite's dynamic import polyfill has been removed. Please install and import https://github.com/GoogleChromeLabs/dynamic-import-polyfill instead.` +) diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 77b27feceddaec..907632b4cacfbf 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -20,7 +20,6 @@ import { getAssetFilename } from './asset' import { isCSSRequest, chunkToEmittedCssFileMap } from './css' -import { polyfillId } from './dynamicImportPolyfill' import { AttributeNode, NodeTransform, @@ -261,12 +260,6 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { } processedHtml.set(id, s.toString()) - - // inject dynamic import polyfill - if (config.build.polyfillDynamicImport) { - js = `import "${polyfillId}";\n${js}` - } - return js } }, diff --git a/packages/vite/src/node/plugins/importAnalysisBuild.ts b/packages/vite/src/node/plugins/importAnalysisBuild.ts index 8ba83f3ea89dd1..91c9da7e9ca6ba 100644 --- a/packages/vite/src/node/plugins/importAnalysisBuild.ts +++ b/packages/vite/src/node/plugins/importAnalysisBuild.ts @@ -205,7 +205,6 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin { return } - const isPolyfillEnabled = config.build.polyfillDynamicImport for (const file in bundle) { const chunk = bundle[file] // can't use chunk.dynamicImports.length here since some modules e.g. @@ -222,12 +221,7 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin { if (imports.length) { const s = new MagicString(code) for (let index = 0; index < imports.length; index++) { - const { s: start, e: end, d: dynamicIndex } = imports[index] - // if dynamic import polyfill is used, rewrite the import to - // use the polyfilled function. - if (isPolyfillEnabled) { - s.overwrite(dynamicIndex, dynamicIndex + 6, `__import__`) - } + const { s: start, e: end } = imports[index] // check the chunk being imported const url = code.slice(start, end) const deps: Set = new Set() diff --git a/packages/vite/src/node/plugins/index.ts b/packages/vite/src/node/plugins/index.ts index 44ccb057f2389e..dd26e4260129b8 100644 --- a/packages/vite/src/node/plugins/index.ts +++ b/packages/vite/src/node/plugins/index.ts @@ -11,7 +11,6 @@ import { clientInjectionsPlugin } from './clientInjections' import { htmlInlineScriptProxyPlugin } from './html' import { wasmPlugin } from './wasm' import { webWorkerPlugin } from './worker' -import { dynamicImportPolyfillPlugin } from './dynamicImportPolyfill' import { preAliasPlugin } from './preAlias' import { definePlugin } from './define' @@ -31,9 +30,6 @@ export async function resolvePlugins( isBuild ? null : preAliasPlugin(), aliasPlugin({ entries: config.resolve.alias }), ...prePlugins, - config.build.polyfillDynamicImport - ? dynamicImportPolyfillPlugin(config) - : null, resolvePlugin({ ...config.resolve, root: config.root, diff --git a/scripts/jestPerTestSetup.ts b/scripts/jestPerTestSetup.ts index 5ddc938db28357..fb3f492a9fbf2d 100644 --- a/scripts/jestPerTestSetup.ts +++ b/scripts/jestPerTestSetup.ts @@ -78,8 +78,7 @@ beforeAll(async () => { host: true }, build: { - // skip transpilation and dynamic import polyfills during tests to - // make it faster + // skip transpilation during tests to make it faster target: 'esnext' } } diff --git a/yarn.lock b/yarn.lock index 252621bb86d0a4..3bdcdcdb37b7a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2908,10 +2908,10 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -esbuild@^0.9.3: - version "0.9.7" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.9.7.tgz#ea0d639cbe4b88ec25fbed4d6ff00c8d788ef70b" - integrity sha512-VtUf6aQ89VTmMLKrWHYG50uByMF4JQlVysb8dmg6cOgW8JnFCipmz7p+HNBl+RR3LLCuBxFGVauAe2wfnF9bLg== +esbuild@^0.11.18: + version "0.11.18" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.18.tgz#b587ec9e84d2e291b545e3c6342b5b703fd009cb" + integrity sha512-KD7v4N9b5B8bxPUNn/3GA9r0HWo4nJk3iwjZ+2zG1ffg+r8ig+wqj7sW6zgI6Sn4/B2FnbzqWxcAokAGGM5zwQ== escalade@^3.1.1: version "3.1.1"