Skip to content

Commit cabdae7

Browse files
fix: Add extensionAlias for ESM TS to webpack-batteries-included (#31994)
* chore: Add extensionAlias for ESM TS to webpack-batteries-included For TypeScript ESM projects that use module resolution requiring file extensions, `.js` extension must be used for `.ts` imports. Take advantage of `resolve.extensionAlias` to resolve these imports. Fixes #26827 Fixes #28805 * (Revisions) chore: Add extensionAlias for ESM TS to webpack-batteries-included - Update typescript regex to allow .mts files - Add ESM import tests * chore: add changelog entry * make sure extensionAlias is backwards compatible --------- Co-authored-by: Bill Glesias <bglesias@gmail.com>
1 parent 60d4517 commit cabdae7

File tree

6 files changed

+25
-4
lines changed

6 files changed

+25
-4
lines changed

.circleci/cache-version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Bump this version to force CI to re-create the cache from scratch.
22

3-
5-14-2025
3+
7-15-2025

cli/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ _Released 7/30/2025 (PENDING)_
66
**Bugfixes:**
77

88
- Fixed missing support for setting an absolute path for `component.indexHtmlFile` in `@cypress/webpack-dev-server`. Fixes [#31819](https://github.com/cypress-io/cypress/issues/31819).
9+
- Fixed an issue where TypeScript ESM projects using `.js` and `.mjs` extensions where not resolving correctly within `@cypress/webpack-batteries-included-preprocessor`. Addressed in [#31994](https://github.com/cypress-io/cypress/pull/31994).
910

1011
## 14.5.2
1112

npm/webpack-batteries-included-preprocessor/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPl
77
const debug = Debug('cypress:webpack-batteries-included-preprocessor')
88
const WBADebugNamespace = 'cypress-verbose:webpack-batteries-included-preprocessor:bundle-analyzer'
99

10+
const typescriptExtensionRegex = /\.m?tsx?$/
11+
1012
const hasTsLoader = (rules) => {
1113
return rules.some((rule) => {
1214
if (!rule.use || !Array.isArray(rule.use)) return false
@@ -45,7 +47,7 @@ const addTypeScriptConfig = (file, options) => {
4547
configFile ? debug(`found user tsconfig.json at ${configFile?.path} with compilerOptions: ${JSON.stringify(configFile?.config?.compilerOptions)}`) : debug('no user tsconfig.json found')
4648

4749
webpackOptions.module.rules.push({
48-
test: /\.tsx?$/,
50+
test: typescriptExtensionRegex,
4951
exclude: [/node_modules/],
5052
use: [
5153
{
@@ -61,6 +63,7 @@ const addTypeScriptConfig = (file, options) => {
6163
})
6264

6365
webpackOptions.resolve.extensions = webpackOptions.resolve.extensions.concat(['.ts', '.tsx'])
66+
webpackOptions.resolve.extensionAlias = webpackOptions.resolve.extensionAlias || { '.js': ['.ts', '.js'], '.mjs': ['.mts', '.mjs'] }
6467
webpackOptions.resolve.plugins = [new TsconfigPathsPlugin({
6568
configFile: configFile?.path,
6669
silent: true,
@@ -188,8 +191,6 @@ const getDefaultWebpackOptions = () => {
188191
}
189192
}
190193

191-
const typescriptExtensionRegex = /\.tsx?$/
192-
193194
const preprocessor = (options = {}) => {
194195
return (file) => {
195196
if (!options.typescript && typescriptExtensionRegex.test(file.filePath)) {

npm/webpack-batteries-included-preprocessor/test/e2e/features.spec.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ describe('webpack-batteries-included-preprocessor features', () => {
9090
await runAndEval('typescript_imports_spec.js', { ...options })
9191
})
9292

93+
it('handles importing ESM .ts and .mts', async () => {
94+
await runAndEval('typescript_esm_imports_spec.js', { ...options })
95+
})
96+
9397
it('handles esModuleInterop: false (default)', async () => {
9498
await runAndEval('typescript_esmoduleinterop_false_spec.ts', { ...options })
9599
})
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// simple example of typescript types
2+
type SomeMtsType = {
3+
mtsProp: string
4+
}
5+
6+
export const mtsTypeExample: SomeMtsType = { mtsProp: 'mts value' }
7+
8+
export const fromMts = 'from mts'
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { fromTs, tsTypeExample } from './file-types/ts-file.js'
2+
import { fromMts, mtsTypeExample } from './file-types/mts-file.mjs'
3+
4+
expect(fromTs).equal('from ts')
5+
expect(tsTypeExample.tsProp).equal('ts value')
6+
expect(fromMts).equal('from mts')
7+
expect(mtsTypeExample.mtsProp).equal('mts value')

0 commit comments

Comments
 (0)