Skip to content

Commit

Permalink
feat: export transformWithEsbuild (#4882)
Browse files Browse the repository at this point in the history
* feat: export transformWithEsbuild

* chore: add tests

* fix: test typo

Co-authored-by: Dominik G. <dominik.goepel@gmx.de>

* chore: deprecate server.transformWithEsbuild

* docs: add transformWithEsbuild

Co-authored-by: Dominik G. <dominik.goepel@gmx.de>
  • Loading branch information
bluwy and dominikg committed Sep 18, 2021
1 parent c749994 commit c8c0f74
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 43 deletions.
23 changes: 13 additions & 10 deletions docs/guide/api-javascript.md
Expand Up @@ -87,16 +87,6 @@ interface ViteDevServer {
* Apply Vite built-in HTML transforms and any plugin HTML transforms.
*/
transformIndexHtml(url: string, html: string): Promise<string>
/**
* Util for transforming a file with esbuild.
* Can be useful for certain plugins.
*/
transformWithEsbuild(
code: string,
filename: string,
options?: EsbuildTransformOptions,
inMap?: object
): Promise<ESBuildTransformResult>
/**
* Load a given URL as an instantiated module for SSR.
*/
Expand Down Expand Up @@ -159,3 +149,16 @@ async function resolveConfig(
defaultMode?: string
): Promise<ResolvedConfig>
```

## `transformWithEsbuild`

**Type Signature:**

```ts
async function transformWithEsbuild(
code: string,
filename: string,
options?: EsbuildTransformOptions,
inMap?: object
): Promise<ESBuildTransformResult>
```
39 changes: 39 additions & 0 deletions packages/playground/tsconfig-json/__tests__/tsconfig-json.spec.ts
@@ -1,3 +1,7 @@
import path from 'path'
import fs from 'fs'
import { transformWithEsbuild } from 'vite'

test('should respected each `tsconfig.json`s compilerOptions', () => {
// main side effect should be called (because of `"importsNotUsedAsValues": "preserve"`)
expect(browserLogs).toContain('main side effect')
Expand All @@ -14,3 +18,38 @@ test('should respected each `tsconfig.json`s compilerOptions', () => {
// nested-with-extends base setter should be called (because of `"useDefineForClassFields": false"`)
expect(browserLogs).toContain('data setter in NestedWithExtendsBase')
})

describe('transformWithEsbuild', () => {
test('merge tsconfigRaw object', async () => {
const main = path.resolve(__dirname, '../src/main.ts')
const mainContent = fs.readFileSync(main, 'utf-8')
const result = await transformWithEsbuild(mainContent, main, {
tsconfigRaw: {
compilerOptions: {
useDefineForClassFields: false
}
}
})
// "importsNotUsedAsValues": "preserve" from tsconfig.json should still work
expect(result.code).toContain(
'import { MainTypeOnlyClass } from "./not-used-type";'
)
})

test('overwrite tsconfigRaw string', async () => {
const main = path.resolve(__dirname, '../src/main.ts')
const mainContent = fs.readFileSync(main, 'utf-8')
const result = await transformWithEsbuild(mainContent, main, {
tsconfigRaw: `{
"compilerOptions": {
"useDefineForClassFields": false
}
}`
})
// "importsNotUsedAsValues": "preserve" from tsconfig.json should not be read
// and defaults to "remove"
expect(result.code).not.toContain(
'import { MainTypeOnlyClass } from "./not-used-type";'
)
})
})
2 changes: 2 additions & 0 deletions packages/vite/src/node/index.ts
Expand Up @@ -4,6 +4,7 @@ export { build } from './build'
export { optimizeDeps } from './optimizer'
export { send } from './server/send'
export { createLogger } from './logger'
export { transformWithEsbuild } from './plugins/esbuild'
export { resolvePackageData, resolvePackageEntry } from './plugins/resolve'
export { normalizePath } from './utils'

Expand Down Expand Up @@ -51,6 +52,7 @@ export type {
} from './plugins/html'
export type { CSSOptions, CSSModulesOptions } from './plugins/css'
export type { JsonOptions } from './plugins/json'
export type { TransformOptions as EsbuildTransformOptions } from 'esbuild'
export type { ESBuildOptions, ESBuildTransformResult } from './plugins/esbuild'
export type { Manifest, ManifestChunk } from './plugins/manifest'
export type {
Expand Down
84 changes: 51 additions & 33 deletions packages/vite/src/node/plugins/esbuild.ts
Expand Up @@ -50,52 +50,70 @@ export async function transformWithEsbuild(
options?: TransformOptions,
inMap?: object
): Promise<ESBuildTransformResult> {
// if the id ends with a valid ext, use it (e.g. vue blocks)
// otherwise, cleanup the query before checking the ext
const ext = path.extname(
/\.\w+$/.test(filename) ? filename : cleanUrl(filename)
)
let loader = options?.loader

if (!loader) {
// if the id ends with a valid ext, use it (e.g. vue blocks)
// otherwise, cleanup the query before checking the ext
const ext = path
.extname(/\.\w+$/.test(filename) ? filename : cleanUrl(filename))
.slice(1)

let loader = ext.slice(1)
if (loader === 'cjs' || loader === 'mjs') {
loader = 'js'
if (ext === 'cjs' || ext === 'mjs') {
loader = 'js'
} else {
loader = ext as Loader
}
}

// these fields would affect the compilation result
// https://esbuild.github.io/content-types/#tsconfig-json
const meaningfulFields: Array<keyof TSCompilerOptions> = [
'jsxFactory',
'jsxFragmentFactory',
'useDefineForClassFields',
'importsNotUsedAsValues'
]
const compilerOptionsForFile: TSCompilerOptions = {}
if (loader === 'ts' || loader === 'tsx') {
const loadedTsconfig = await loadTsconfigJsonForFile(filename)
const loadedCompilerOptions = loadedTsconfig.compilerOptions ?? {}

for (const field of meaningfulFields) {
if (field in loadedCompilerOptions) {
// @ts-ignore TypeScript can't tell they are of the same type
compilerOptionsForFile[field] = loadedCompilerOptions[field]
let tsconfigRaw = options?.tsconfigRaw

// if options provide tsconfigraw in string, it takes highest precedence
if (typeof tsconfigRaw !== 'string') {
// these fields would affect the compilation result
// https://esbuild.github.io/content-types/#tsconfig-json
const meaningfulFields: Array<keyof TSCompilerOptions> = [
'jsxFactory',
'jsxFragmentFactory',
'useDefineForClassFields',
'importsNotUsedAsValues'
]
const compilerOptionsForFile: TSCompilerOptions = {}
if (loader === 'ts' || loader === 'tsx') {
const loadedTsconfig = await loadTsconfigJsonForFile(filename)
const loadedCompilerOptions = loadedTsconfig.compilerOptions ?? {}

for (const field of meaningfulFields) {
if (field in loadedCompilerOptions) {
// @ts-ignore TypeScript can't tell they are of the same type
compilerOptionsForFile[field] = loadedCompilerOptions[field]
}
}

// align with TypeScript 4.3
// https://github.com/microsoft/TypeScript/pull/42663
if (loadedCompilerOptions.target?.toLowerCase() === 'esnext') {
compilerOptionsForFile.useDefineForClassFields =
loadedCompilerOptions.useDefineForClassFields ?? true
}
}

// align with TypeScript 4.3
// https://github.com/microsoft/TypeScript/pull/42663
if (loadedCompilerOptions.target?.toLowerCase() === 'esnext') {
compilerOptionsForFile.useDefineForClassFields =
loadedCompilerOptions.useDefineForClassFields ?? true
tsconfigRaw = {
...tsconfigRaw,
compilerOptions: {
...compilerOptionsForFile,
...tsconfigRaw?.compilerOptions
}
}
}

const resolvedOptions = {
loader: loader as Loader,
sourcemap: true,
// ensure source file name contains full query
sourcefile: filename,
tsconfigRaw: { compilerOptions: compilerOptionsForFile },
...options
...options,
loader,
tsconfigRaw
} as ESBuildOptions

delete resolvedOptions.include
Expand Down
2 changes: 2 additions & 0 deletions packages/vite/src/node/server/index.ts
Expand Up @@ -237,6 +237,8 @@ export interface ViteDevServer {
/**
* Util for transforming a file with esbuild.
* Can be useful for certain plugins.
*
* @deprecated import `transformWithEsbuild` from `vite` instead
*/
transformWithEsbuild(
code: string,
Expand Down

0 comments on commit c8c0f74

Please sign in to comment.