Skip to content

Commit a2b3131

Browse files
authoredJul 14, 2022
refactor: always load config with esbuild bundled code (#9121)
1 parent c2426d1 commit a2b3131

File tree

3 files changed

+45
-57
lines changed

3 files changed

+45
-57
lines changed
 

‎packages/vite/src/node/config.ts

+40-55
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
dynamicImport,
2828
isExternalUrl,
2929
isObject,
30-
isTS,
3130
lookupFile,
3231
mergeAlias,
3332
mergeConfig,
@@ -816,7 +815,6 @@ export async function loadConfigFromFile(
816815
const getTime = () => `${(performance.now() - start).toFixed(2)}ms`
817816

818817
let resolvedPath: string | undefined
819-
let dependencies: string[] = []
820818

821819
if (configFile) {
822820
// explicit config path is always resolved from cwd
@@ -852,42 +850,13 @@ export async function loadConfigFromFile(
852850
}
853851

854852
try {
855-
let userConfig: UserConfigExport | undefined
856-
857-
if (isESM) {
858-
const fileUrl = pathToFileURL(resolvedPath)
859-
const bundled = await bundleConfigFile(resolvedPath, true)
860-
dependencies = bundled.dependencies
861-
862-
if (isTS(resolvedPath)) {
863-
// before we can register loaders without requiring users to run node
864-
// with --experimental-loader themselves, we have to do a hack here:
865-
// bundle the config file w/ ts transforms first, write it to disk,
866-
// load it with native Node ESM, then delete the file.
867-
fs.writeFileSync(resolvedPath + '.mjs', bundled.code)
868-
try {
869-
userConfig = (await dynamicImport(`${fileUrl}.mjs?t=${Date.now()}`))
870-
.default
871-
} finally {
872-
fs.unlinkSync(resolvedPath + '.mjs')
873-
}
874-
debug(`TS + native esm config loaded in ${getTime()}`, fileUrl)
875-
} else {
876-
// using Function to avoid this from being compiled away by TS/Rollup
877-
// append a query so that we force reload fresh config in case of
878-
// server restart
879-
userConfig = (await dynamicImport(`${fileUrl}?t=${Date.now()}`)).default
880-
debug(`native esm config loaded in ${getTime()}`, fileUrl)
881-
}
882-
}
883-
884-
if (!userConfig) {
885-
// Bundle config file and transpile it to cjs using esbuild.
886-
const bundled = await bundleConfigFile(resolvedPath)
887-
dependencies = bundled.dependencies
888-
userConfig = await loadConfigFromBundledFile(resolvedPath, bundled.code)
889-
debug(`bundled config file loaded in ${getTime()}`)
890-
}
853+
const bundled = await bundleConfigFile(resolvedPath, isESM)
854+
const userConfig = await loadConfigFromBundledFile(
855+
resolvedPath,
856+
bundled.code,
857+
isESM
858+
)
859+
debug(`bundled config file loaded in ${getTime()}`)
891860

892861
const config = await (typeof userConfig === 'function'
893862
? userConfig(configEnv)
@@ -898,7 +867,7 @@ export async function loadConfigFromFile(
898867
return {
899868
path: normalizePath(resolvedPath),
900869
config,
901-
dependencies
870+
dependencies: bundled.dependencies
902871
}
903872
} catch (e) {
904873
createLogger(logLevel).error(
@@ -911,7 +880,7 @@ export async function loadConfigFromFile(
911880

912881
async function bundleConfigFile(
913882
fileName: string,
914-
isESM = false
883+
isESM: boolean
915884
): Promise<{ code: string; dependencies: string[] }> {
916885
const importMetaUrlVarName = '__vite_injected_original_import_meta_url'
917886
const result = await build({
@@ -954,7 +923,7 @@ async function bundleConfigFile(
954923
)};`
955924

956925
return {
957-
loader: isTS(args.path) ? 'ts' : 'js',
926+
loader: args.path.endsWith('ts') ? 'ts' : 'js',
958927
contents: injectValues + contents
959928
}
960929
})
@@ -976,22 +945,38 @@ interface NodeModuleWithCompile extends NodeModule {
976945
const _require = createRequire(import.meta.url)
977946
async function loadConfigFromBundledFile(
978947
fileName: string,
979-
bundledCode: string
980-
): Promise<UserConfig> {
981-
const realFileName = fs.realpathSync(fileName)
982-
const defaultLoader = _require.extensions['.js']
983-
_require.extensions['.js'] = (module: NodeModule, filename: string) => {
984-
if (filename === realFileName) {
985-
;(module as NodeModuleWithCompile)._compile(bundledCode, filename)
986-
} else {
987-
defaultLoader(module, filename)
948+
bundledCode: string,
949+
isESM: boolean
950+
): Promise<UserConfigExport> {
951+
// for esm, before we can register loaders without requiring users to run node
952+
// with --experimental-loader themselves, we have to do a hack here:
953+
// write it to disk, load it with native Node ESM, then delete the file.
954+
if (isESM) {
955+
const fileUrl = pathToFileURL(fileName)
956+
fs.writeFileSync(fileName + '.mjs', bundledCode)
957+
try {
958+
return (await dynamicImport(`${fileUrl}.mjs?t=${Date.now()}`)).default
959+
} finally {
960+
fs.unlinkSync(fileName + '.mjs')
961+
}
962+
}
963+
// for cjs, we can register a custom loader via `_require.extensions`
964+
else {
965+
const realFileName = fs.realpathSync(fileName)
966+
const defaultLoader = _require.extensions['.js']
967+
_require.extensions['.js'] = (module: NodeModule, filename: string) => {
968+
if (filename === realFileName) {
969+
;(module as NodeModuleWithCompile)._compile(bundledCode, filename)
970+
} else {
971+
defaultLoader(module, filename)
972+
}
988973
}
974+
// clear cache in case of server restart
975+
delete _require.cache[_require.resolve(fileName)]
976+
const raw = _require(fileName)
977+
_require.extensions['.js'] = defaultLoader
978+
return raw.__esModule ? raw.default : raw
989979
}
990-
// clear cache in case of server restart
991-
delete _require.cache[_require.resolve(fileName)]
992-
const raw = _require(fileName)
993-
_require.extensions['.js'] = defaultLoader
994-
return raw.__esModule ? raw.default : raw
995980
}
996981

997982
export function getDepOptimizationConfig(

‎packages/vite/src/node/utils.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1130,8 +1130,6 @@ export function stripBomTag(content: string): string {
11301130
return content
11311131
}
11321132

1133-
export const isTS = (filename: string): boolean => /\.[cm]?ts$/.test(filename)
1134-
11351133
const windowsDrivePathPrefixRE = /^[A-Za-z]:[/\\]/
11361134

11371135
/**

‎playground/ssr-vue/vite.config.js

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ const nestedVirtualId = '\0' + nestedVirtualFile
1010

1111
const base = '/test/'
1212

13+
// preserve this to test loading __filename & __dirname in ESM as Vite polyfills them.
14+
// if Vite incorrectly load this file, node.js would error out.
15+
globalThis.__vite_test_filename = __filename
16+
globalThis.__vite_test_dirname = __dirname
17+
1318
export default defineConfig(({ command, ssrBuild }) => ({
1419
base,
1520
plugins: [

0 commit comments

Comments
 (0)
Please sign in to comment.