From 8eba8a18e14723663441b3e098f3508a3f026931 Mon Sep 17 00:00:00 2001 From: EGOIST <0x142857@gmail.com> Date: Sun, 14 Mar 2021 19:45:38 +0800 Subject: [PATCH 1/3] feat: bump esbuild --- packages/vite/package.json | 2 +- packages/vite/src/node/config.ts | 4 +-- .../src/node/optimizer/esbuildDepPlugin.ts | 4 +-- packages/vite/src/node/optimizer/index.ts | 15 +++----- packages/vite/src/node/optimizer/scan.ts | 8 ++--- packages/vite/src/node/plugins/esbuild.ts | 35 +++---------------- yarn.lock | 8 ++--- 7 files changed, 20 insertions(+), 56 deletions(-) diff --git a/packages/vite/package.json b/packages/vite/package.json index ecfcb525bb3e1e..b1a9065e19c9b3 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -44,7 +44,7 @@ }, "//": "READ .github/contributing.md to understand what to put under deps vs. devDeps!", "dependencies": { - "esbuild": "^0.8.52", + "esbuild": "^0.9.2", "postcss": "^8.2.1", "resolve": "^1.19.0", "rollup": "^2.38.5" diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index d985048c499d68..387e57a6e47c45 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -14,7 +14,7 @@ import { } from './utils' import { resolvePlugins } from './plugins' import chalk from 'chalk' -import { ESBuildOptions, esbuildPlugin, stopService } from './plugins/esbuild' +import { ESBuildOptions, esbuildPlugin } from './plugins/esbuild' import dotenv from 'dotenv' import dotenvExpand from 'dotenv-expand' import { Alias, AliasOptions } from 'types/alias' @@ -715,8 +715,6 @@ export async function loadConfigFromFile( chalk.red(`failed to load config from ${resolvedPath}`) ) throw e - } finally { - await stopService() } } diff --git a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts index 47f4cd017ca1ab..19d758c6c3fe53 100644 --- a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts +++ b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts @@ -1,5 +1,5 @@ import path from 'path' -import { Loader, Plugin, ResolveKind } from 'esbuild' +import { Loader, Plugin, ImportKind } from 'esbuild' import { KNOWN_ASSET_TYPES } from '../constants' import { ResolvedConfig } from '..' import { @@ -47,7 +47,7 @@ export function esbuildDepPlugin( const resolve = ( id: string, importer: string, - kind: ResolveKind, + kind: ImportKind, resolveDir?: string ): Promise => { let _importer diff --git a/packages/vite/src/node/optimizer/index.ts b/packages/vite/src/node/optimizer/index.ts index 97f2ca06bb6ea0..b712ef81c700a5 100644 --- a/packages/vite/src/node/optimizer/index.ts +++ b/packages/vite/src/node/optimizer/index.ts @@ -2,6 +2,7 @@ import fs from 'fs' import path from 'path' import chalk from 'chalk' import { createHash } from 'crypto' +import { build } from 'esbuild' import { ResolvedConfig } from '../config' import { createDebugger, @@ -14,7 +15,6 @@ import { import { esbuildDepPlugin } from './esbuildDepPlugin' import { ImportSpecifier, init, parse } from 'es-module-lexer' import { scanImports } from './scan' -import { ensureService, stopService } from '../plugins/esbuild' const debug = createDebugger('vite:deps') @@ -191,8 +191,6 @@ export async function optimizeDeps( logger.info(chalk.greenBright(`Optimizing dependencies:\n ${depsString}`)) } - const esbuildMetaPath = path.join(cacheDir, '_esbuild.json') - // esbuild generates nested directory output with lowest common ancestor base // this is unpredictable and makes it difficult to analyze entry / output // mapping. So what we do here is: @@ -227,8 +225,8 @@ export async function optimizeDeps( } const start = Date.now() - const esbuildService = await ensureService() - await esbuildService.build({ + + const result = await build({ entryPoints: Object.keys(flatIdDeps), bundle: true, keepNames: true, @@ -239,12 +237,12 @@ export async function optimizeDeps( sourcemap: true, outdir: cacheDir, treeShaking: 'ignore-annotations', - metafile: esbuildMetaPath, + metafile: true, define, plugins: [esbuildDepPlugin(flatIdDeps, flatIdToExports, config)] }) - const meta = JSON.parse(fs.readFileSync(esbuildMetaPath, 'utf-8')) + const meta = result.metafile! for (const id in deps) { const entry = deps[id] @@ -256,9 +254,6 @@ export async function optimizeDeps( } writeFile(dataPath, JSON.stringify(data, null, 2)) - if (asCommand) { - await stopService() - } debug(`deps bundled in ${Date.now() - start}ms`) return data diff --git a/packages/vite/src/node/optimizer/scan.ts b/packages/vite/src/node/optimizer/scan.ts index 239d40fad406b5..b6449239c20819 100644 --- a/packages/vite/src/node/optimizer/scan.ts +++ b/packages/vite/src/node/optimizer/scan.ts @@ -2,7 +2,7 @@ import fs from 'fs' import path from 'path' import glob from 'fast-glob' import { ResolvedConfig } from '..' -import { Loader, Plugin } from 'esbuild' +import { Loader, Plugin, build, transform } from 'esbuild' import { KNOWN_ASSET_TYPES, JS_TYPES_RE, @@ -25,7 +25,6 @@ import { import { init, parse } from 'es-module-lexer' import MagicString from 'magic-string' import { transformImportGlob } from '../importGlob' -import { ensureService } from '../plugins/esbuild' const debug = createDebugger('vite:deps') @@ -82,10 +81,9 @@ export async function scanImports( const container = await createPluginContainer(config) const plugin = esbuildScanPlugin(config, container, deps, missing, entries) - const esbuildService = await ensureService() await Promise.all( entries.map((entry) => - esbuildService.build({ + build({ entryPoints: [entry], bundle: true, format: 'esm', @@ -362,7 +360,7 @@ async function transformGlob( ) { // transform the content first since es-module-lexer can't handle non-js if (loader !== 'js') { - source = (await (await ensureService()).transform(source, { loader })).code + source = (await transform(source, { loader })).code } await init diff --git a/packages/vite/src/node/plugins/esbuild.ts b/packages/vite/src/node/plugins/esbuild.ts index 7aa1d31e0522a1..2910388d53db98 100644 --- a/packages/vite/src/node/plugins/esbuild.ts +++ b/packages/vite/src/node/plugins/esbuild.ts @@ -2,7 +2,7 @@ import path from 'path' import chalk from 'chalk' import { Plugin } from '../plugin' import { - Service, + transform, Message, Loader, TransformOptions, @@ -16,30 +16,12 @@ import { createFilter } from '@rollup/pluginutils' const debug = createDebugger('vite:esbuild') -// lazy start the service -let _servicePromise: Promise | 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() - } - return _servicePromise! -} - -export async function stopService() { - if (_servicePromise) { - const service = await _servicePromise - service.stop() - _servicePromise = undefined - } -} - export type ESBuildTransformResult = Omit & { map: SourceMap } @@ -50,18 +32,17 @@ export async function transformWithEsbuild( options?: TransformOptions, inMap?: object ): Promise { - const service = await ensureService() // 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 = ext.slice(1) if (loader === 'cjs' || loader === 'mjs') { loader = 'js' } - + const resolvedOptions = { loader: loader as Loader, sourcemap: true, @@ -75,7 +56,7 @@ export async function transformWithEsbuild( delete resolvedOptions.jsxInject try { - const result = await service.transform(code, resolvedOptions) + const result = await transform(code, resolvedOptions) if (inMap) { const nextMap = JSON.parse(result.map) // merge-source-map will overwrite original sources if newMap also has @@ -129,10 +110,6 @@ export function esbuildPlugin(options: ESBuildOptions = {}): Plugin { map: result.map } } - }, - - async closeBundle() { - await stopService() } } } @@ -155,10 +132,6 @@ export const buildEsbuildPlugin = (config: ResolvedConfig): Plugin => { target: target || undefined, minify }) - }, - - async closeBundle() { - await stopService() } } } diff --git a/yarn.lock b/yarn.lock index 324fcea97657eb..85f2f3c2d8e20e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2812,10 +2812,10 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -esbuild@^0.8.52: - version "0.8.52" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.8.52.tgz#6dabf11c517af449a96d66da20dfc204ee7b5294" - integrity sha512-b5KzFweLLXoXQwdC/e2+Z80c8uo2M5MgP7yQEEebkFw6In4T9CvYcNoM2ElvJt8ByO04zAZUV0fZkXmXoi2s9A== +esbuild@^0.9.2: + version "0.9.2" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.9.2.tgz#7e9fde247c913ed8ee059e2648b0c53f7d00abe5" + integrity sha512-xE3oOILjnmN8PSjkG3lT9NBbd1DbxNqolJ5qNyrLhDWsFef3yTp/KTQz1C/x7BYFKbtrr9foYtKA6KA1zuNAUQ== escalade@^3.1.1: version "3.1.1" From 2da008485b567040314f58c6a8ebadf5cf303fb5 Mon Sep 17 00:00:00 2001 From: EGOIST <0x142857@gmail.com> Date: Mon, 15 Mar 2021 21:04:25 +0800 Subject: [PATCH 2/3] feat: bundle vite config file with esbuild --- packages/vite/src/node/config.ts | 70 +++++++++++++++++--------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 387e57a6e47c45..2ff166042ebd43 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -1,7 +1,6 @@ import fs from 'fs' import path from 'path' import { Plugin } from './plugin' -import Rollup from 'rollup' import { BuildOptions, resolveBuildOptions } from './build' import { ServerOptions } from './server' import { CSSOptions } from './plugins/css' @@ -14,7 +13,7 @@ import { } from './utils' import { resolvePlugins } from './plugins' import chalk from 'chalk' -import { ESBuildOptions, esbuildPlugin } from './plugins/esbuild' +import { ESBuildOptions } from './plugins/esbuild' import dotenv from 'dotenv' import dotenvExpand from 'dotenv-expand' import { Alias, AliasOptions } from 'types/alias' @@ -35,6 +34,7 @@ import { PluginContainer } from './server/pluginContainer' import aliasPlugin from '@rollup/plugin-alias' +import { build } from 'esbuild' const debug = createDebugger('vite:config') @@ -722,43 +722,49 @@ async function bundleConfigFile( fileName: string, mjs = false ): Promise { - const rollup = require('rollup') as typeof Rollup - // node-resolve must be imported since it's bundled - const bundle = await rollup.rollup({ - external: (id: string) => - (id[0] !== '.' && !path.isAbsolute(id)) || - id.slice(-5, id.length) === '.json', - input: fileName, - treeshake: false, + const result = await build({ + entryPoints: [fileName], + outfile: '/out.js', + write: false, + platform: 'node', + bundle: true, + format: mjs ? 'esm' : 'cjs', plugins: [ - // use esbuild + node-resolve to support .ts files - esbuildPlugin({ target: 'esnext' }), - resolvePlugin({ - root: path.dirname(fileName), - isBuild: true, - asSrc: false, - isProduction: false - }), + { + name: 'externalize-deps', + setup(build) { + build.onResolve({ filter: /.*/ }, (args) => { + const id = args.path + if ( + (id[0] !== '.' && !path.isAbsolute(id)) || + id.slice(-5, id.length) === '.json' + ) { + return { + external: true + } + } + }) + } + }, { name: 'replace-import-meta', - transform(code, id) { - return code.replace( - /\bimport\.meta\.url\b/g, - JSON.stringify(`file://${id}`) - ) + setup(build) { + build.onLoad({ filter: /\.[jt]s$/ }, async (args) => { + const contents = await fs.promises.readFile(args.path, 'utf8') + return { + loader: args.path.endsWith('.ts') ? 'ts' : 'js', + contents: contents.replace( + /\bimport\.meta\.url\b/g, + JSON.stringify(`file://${args.path}`) + ) + } + }) } } ] }) - - const { - output: [{ code }] - } = await bundle.generate({ - exports: mjs ? 'auto' : 'named', - format: mjs ? 'es' : 'cjs' - }) - - return code + const { text } = result.outputFiles.find((file) => file.path === '/out.js')! + return text } interface NodeModuleWithCompile extends NodeModule { From a7d4c93c23569898185a0264e20a82bb99813be8 Mon Sep 17 00:00:00 2001 From: EGOIST <0x142857@gmail.com> Date: Mon, 15 Mar 2021 21:18:49 +0800 Subject: [PATCH 3/3] fix: use the first item of output files --- packages/vite/src/node/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 2ff166042ebd43..2a5e0e7cbffcf7 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -724,7 +724,7 @@ async function bundleConfigFile( ): Promise { const result = await build({ entryPoints: [fileName], - outfile: '/out.js', + outfile: 'out.js', write: false, platform: 'node', bundle: true, @@ -763,7 +763,7 @@ async function bundleConfigFile( } ] }) - const { text } = result.outputFiles.find((file) => file.path === '/out.js')! + const { text } = result.outputFiles[0] return text }