Files
msw/config/plugins/esbuild/forceEsmExtensionsPlugin.ts

69 lines
2.0 KiB
TypeScript

import { type Plugin } from 'esbuild'
export const ESM_EXTENSION = '.mjs'
export const CJS_EXTENSION = '.js'
export function forceEsmExtensionsPlugin(): Plugin {
return {
name: 'forceEsmExtensionsPlugin',
setup(build) {
const isEsm = build.initialOptions.format === 'esm'
build.onEnd(async (result) => {
if (result.errors.length > 0) {
return
}
for (const outputFile of result.outputFiles || []) {
// Only target CJS/ESM files.
// This ignores additional files emitted, like sourcemaps ("*.js.map").
if (
!(
outputFile.path.endsWith(ESM_EXTENSION) ||
outputFile.path.endsWith('.mjs')
)
) {
continue
}
const fileContents = outputFile.text
const nextFileContents = modifyRelativeImports(fileContents, isEsm)
outputFile.contents = Buffer.from(nextFileContents)
}
})
},
}
}
const CJS_RELATIVE_IMPORT_EXP = /require\(["'](\..+)["']\)(;)?/gm
const ESM_RELATIVE_IMPORT_EXP = /from ["'](\..+)["'](;)?/gm
function modifyRelativeImports(contents: string, isEsm: boolean): string {
const extension = isEsm ? ESM_EXTENSION : CJS_EXTENSION
const importExpression = isEsm
? ESM_RELATIVE_IMPORT_EXP
: CJS_RELATIVE_IMPORT_EXP
return contents.replace(
importExpression,
(_, importPath, maybeSemicolon = '') => {
if (importPath.endsWith('.') || importPath.endsWith('/')) {
return isEsm
? `from '${importPath}/index${extension}'${maybeSemicolon}`
: `require("${importPath}/index${extension}")${maybeSemicolon}`
}
if (importPath.endsWith(extension)) {
return isEsm
? `from '${importPath}'${maybeSemicolon}`
: `require("${importPath}")${maybeSemicolon}`
}
return isEsm
? `from '${importPath}${extension}'${maybeSemicolon}`
: `require("${importPath}${extension}")${maybeSemicolon}`
},
)
}