Skip to content

Commit

Permalink
refactor!: esbuild 0.11 upgrade, remove dynamic-import-polyfill (vite…
Browse files Browse the repository at this point in the history
  • Loading branch information
ludofischer authored and fi3ework committed May 22, 2021
1 parent 36d97d6 commit e2324a9
Show file tree
Hide file tree
Showing 15 changed files with 50 additions and 217 deletions.
15 changes: 0 additions & 15 deletions docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
7 changes: 0 additions & 7 deletions docs/guide/backend-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 4 additions & 7 deletions docs/guide/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

Expand Down
1 change: 0 additions & 1 deletion docs/guide/comparisons.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**
Expand Down
6 changes: 0 additions & 6 deletions docs/guide/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<link>` 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.).
Expand Down
4 changes: 1 addition & 3 deletions docs/guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
27 changes: 16 additions & 11 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
/**
Expand Down Expand Up @@ -195,12 +194,13 @@ export interface LibraryOptions {

export type LibraryFormats = 'es' | 'cjs' | 'umd' | 'iife'

export type ResolvedBuildOptions = Required<Omit<BuildOptions, 'base'>>
export type ResolvedBuildOptions = Required<
Omit<BuildOptions, 'base' | 'polyfillDynamicImport'>
>

export function resolveBuildOptions(raw?: BuildOptions): ResolvedBuildOptions {
const resolved: ResolvedBuildOptions = {
target: 'modules',
polyfillDynamicImport: raw?.target !== 'esnext' && !raw?.lib,
outDir: 'dist',
assetsDir: 'assets',
assetsInlineLimit: 4096,
Expand Down Expand Up @@ -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'
Expand Down
19 changes: 19 additions & 0 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.')
}
Expand Down
145 changes: 3 additions & 142 deletions packages/vite/src/node/plugins/dynamicImportPolyfill.ts
Original file line number Diff line number Diff line change
@@ -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.`
)
7 changes: 0 additions & 7 deletions packages/vite/src/node/plugins/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
getAssetFilename
} from './asset'
import { isCSSRequest, chunkToEmittedCssFileMap } from './css'
import { polyfillId } from './dynamicImportPolyfill'
import {
AttributeNode,
NodeTransform,
Expand Down Expand Up @@ -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
}
},
Expand Down
8 changes: 1 addition & 7 deletions packages/vite/src/node/plugins/importAnalysisBuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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<string> = new Set()
Expand Down
4 changes: 0 additions & 4 deletions packages/vite/src/node/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions scripts/jestPerTestSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}
}
Expand Down
Loading

0 comments on commit e2324a9

Please sign in to comment.