Skip to content

Commit

Permalink
feat: esbuild.(include|exclude|jsxInject)
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jan 4, 2021
1 parent 409988f commit b5b1496
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 25 deletions.
18 changes: 14 additions & 4 deletions docs/config/index.md
Expand Up @@ -133,9 +133,9 @@ export default ({ command, mode }) => {

### esbuild

- **Type:** `ESBuildTransformOptions | ((file: string) => ESBuildTransformOptions) | false`
- **Type:** `ESBuildOptions | false`

Specify [esbuild transform options](https://esbuild.github.io/api/#transform-api). The most common use case is customizing JSX:
`ESBuildOptions` extends [ESbuild's own transform options](https://esbuild.github.io/api/#transform-api). The most common use case is customizing JSX:

```js
export default {
Expand All @@ -146,9 +146,19 @@ export default ({ command, mode }) => {
}
```

The option can also be a function to conditionally return options based on the name of the file being transformed.
By default, ESBuild is applied to `ts`, `jsx` and `tsx` files. You can customize this with `esbuild.include` and `esbuild.exclude`, both of which expects type of `string | RegExp | (string | RegExp)[]`.

Set to `false` to disable ESbuild transforms (applies to `.ts`. `.tsx` and `.jsx` files by default).
In addition, you can also use `esbuild.jsxInject` to automatically inject JSX helper imports for every file transformed by ESBuild:

```js
export default {
esbuild: {
jsxInject: `import React from 'react'`
}
}
```

Set to `false` to disable ESbuild transforms.

### assetsInclude

Expand Down
15 changes: 12 additions & 3 deletions docs/guide/features.md
Expand Up @@ -34,7 +34,7 @@ Note that because `esbuild` only performs transpilation without type information

## JSX

`.jsx` and `.tsx` files are also supported out of the box. JSX transpilation is also handled via `esbuild`, and defaults to the React 16 flavor. React 17 style JSX support in esbuild is tracked [here](https://github.com/evanw/esbuild/issues/334).
`.jsx` and `.tsx` files are also supported out of the box. JSX transpilation is also handled via [ESBuild](https://esbuild.github.io), and defaults to the React 16 flavor. React 17 style JSX support in ESBuild is tracked [here](https://github.com/evanw/esbuild/issues/334).

If not using JSX with React, custom `jsxFactory` and `jsxFragment` can be configured using the [`esbuild` option](/config/#esbuild). For example for Preact:

Expand All @@ -48,9 +48,18 @@ export default {
}
```

More details in [esbuild docs](https://esbuild.github.io/content-types/#jsx).
More details in [ESBuild docs](https://esbuild.github.io/content-types/#jsx).

A custom plugin can also auto inject the helpers in every file to avoid having to manually import them. See the [Plugin API](./api-plugin) on how to write such a plugin.
You can inject the JSX helpers using `jsxInject` to avoid manual imports, which is a Vite-only option:

```js
// vite.config.js
export default {
esbuild: {
jsxInject: `import React from 'react'`
}
}
```

## CSS

Expand Down
2 changes: 1 addition & 1 deletion packages/playground/react/App.jsx
@@ -1,4 +1,4 @@
import React, { useState } from 'react'
import { useState } from 'react'

function App() {
const [count, setCount] = useState(0)
Expand Down
5 changes: 4 additions & 1 deletion packages/playground/react/vite.config.js
Expand Up @@ -4,5 +4,8 @@ const reactRefresh = require('@vitejs/plugin-react-refresh')
* @type {import('vite').UserConfig}
*/
module.exports = {
plugins: [reactRefresh()]
plugins: [reactRefresh()],
esbuild: {
jsxInject: `import React from 'react'`
}
}
8 changes: 2 additions & 6 deletions packages/vite/src/node/config.ts
Expand Up @@ -8,8 +8,7 @@ import { CSSOptions } from './plugins/css'
import { createDebugger, isObject, lookupFile, normalizePath } from './utils'
import { resolvePlugins } from './plugins'
import chalk from 'chalk'
import { esbuildPlugin } from './plugins/esbuild'
import { TransformOptions as ESbuildTransformOptions } from 'esbuild'
import { ESBuildOptions, esbuildPlugin } from './plugins/esbuild'
import dotenv from 'dotenv'
import dotenvExpand from 'dotenv-expand'
import { Alias, AliasOptions } from 'types/alias'
Expand Down Expand Up @@ -67,10 +66,7 @@ export interface UserConfig {
* Transform options to pass to esbuild.
* Or set to `false` to disable esbuild.
*/
esbuild?:
| ESbuildTransformOptions
| ((file: string) => ESbuildTransformOptions)

This comment has been minimized.

Copy link
@aleclarson

aleclarson Apr 1, 2021

Member

What's the point in removing esbuild option function?

| false
esbuild?: ESBuildOptions | false
/**
* Specify additional files to be treated as source file (included into the
* transform pipeline).
Expand Down
33 changes: 23 additions & 10 deletions packages/vite/src/node/plugins/esbuild.ts
Expand Up @@ -12,12 +12,19 @@ import { createDebugger, generateCodeFrame } from '../utils'
import merge from 'merge-source-map'
import { SourceMap } from 'rollup'
import { ResolvedConfig } from '..'
import { createFilter } from '@rollup/pluginutils'

const debug = createDebugger('vite:esbuild')

// lazy start the service
let _servicePromise: Promise<Service> | undefined

export interface ESBuildOptions extends TransformOptions {
include?: string | RegExp | string[] | RegExp[]
exclude?: string | RegExp | string[] | RegExp[]
jsxInject?: string
}

export async function ensureService() {
if (!_servicePromise) {
_servicePromise = require('esbuild').startService()
Expand All @@ -40,22 +47,22 @@ export type EsbuildTransformResult = Omit<TransformResult, 'map'> & {
export async function transformWithEsbuild(
code: string,
filename: string,
options?: TransformOptions | ((file: string) => TransformOptions),
options?: TransformOptions,
inMap?: object
): Promise<EsbuildTransformResult> {
const service = await ensureService()

if (typeof options === 'function') {
options = options(filename)
}

const resolvedOptions = {
loader: path.extname(filename).slice(1) as Loader,
sourcemap: true,
// ensure source file name contains full query
sourcefile: filename,
...options
}
} as ESBuildOptions

delete resolvedOptions.include
delete resolvedOptions.exclude
delete resolvedOptions.jsxInject

try {
const result = await service.transform(code, resolvedOptions)
Expand Down Expand Up @@ -88,19 +95,25 @@ export async function transformWithEsbuild(
}
}

export function esbuildPlugin(
options: TransformOptions | ((file: string) => TransformOptions) = {}
): Plugin {
export function esbuildPlugin(options: ESBuildOptions = {}): Plugin {
const filter = createFilter(
options.include || /\.(tsx?|jsx)$/,
options.exclude
)

return {
name: 'vite:esbuild',
async transform(code, id) {
if (/\.(tsx?|jsx)$/.test(id)) {
if (filter(id)) {
const result = await transformWithEsbuild(code, id, options)
if (result.warnings.length) {
result.warnings.forEach((m) => {
this.warn(prettifyMessage(m, code))
})
}
if (options.jsxInject) {
result.code = options.jsxInject + ';' + result.code
}
return {
code: result.code,
map: result.map
Expand Down

0 comments on commit b5b1496

Please sign in to comment.