Issue 1:
Bug report

What is the current behavior?

For the dynamic imports which contains some expression, the resolve.extensionAlias configuration option is not used to resolving the imports.

If the current behavior is a bug, please provide the steps to reproduce.

// Config
const config = {
...
resolve: {
extensions: [ '.ts', '.tsx', '.js', '.jsx' ],
extensionAlias: {
'.js': [ '.js', '.ts', '.tsx' ]
}
}
...
};

// Input:
// /index.ts
const x = 'a';
import(`./lazy-${x}.js`);
// /lazy-a.ts
export {}

// Output:
...
/***/ "./. lazy recursive ^\\.\\/lazy\\-.*\\.js$":
/*!*****************************************************!*\
!*** ././ lazy ^\.\/lazy\-.*\.js$ namespace object ***!
\*****************************************************/
/***/ ((module) => {

function webpackEmptyAsyncContext(req) {
// Here Promise.resolve().then() is used instead of new Promise() to prevent
// uncaught exception popping up in devtools
return Promise.resolve().then(() => {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
});
}
webpackEmptyAsyncContext.keys = () => ([]);
webpackEmptyAsyncContext.resolve = webpackEmptyAsyncContext;
webpackEmptyAsyncContext.id = "./. lazy recursive ^\\.\\/lazy\\-.*\\.js$";
module.exports = webpackEmptyAsyncContext;

/***/ })
...
(() => {
/*!******************!*\
!*** ./index.ts ***!
\******************/
const x = 'a';
__webpack_require__("./. lazy recursive ^\\.\\/lazy\\-.*\\.js$")(`./lazy-${x}.js`);
})();
...

When we will change the code to use .ts extension in the import like:

...
import(`./lazy-${x}.ts`);
...

Or we remove the the extension from the import expression like

...
import(`./lazy-${x}`);
...

The output code is fine and contains the resolution map like:

// Output:
...

/***/ "./. lazy recursive ^\\.\\/lazy\\-.*\\.ts$":
/*!*****************************************************!*\
!*** ././ lazy ^\.\/lazy\-.*\.ts$ namespace object ***!
\*****************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
var map = {
"./lazy-a.ts": [
"./lazy-a.ts",
"lazy-a_ts"
]
};
...

The full gist: https://gist.github.com/majo44/e774abdc4aea027d11df1ee8582e97ee

What is the expected behavior?

In case of es module javascript/typescript code the extensions formally are obligatory, the typescript resolution logic also supports the '.js' extensions. Webpack perfectly handling that for the static imports and for the dynamic imports without expressions by using of provided extensionAlias configuration property. Unfortunately it is not align with the resolution of dynamic imports with expressions. The expectation is to properly resolve the dynamic imports with expression by taking the extensionAlias in consideration.

Other relevant information:

webpack version: 5.80.0

Node.js version: v18.16.0

Operating System: Windows 11

Issue 2:
Bug report

What is the current behavior?

The same problem in require.context and import.meta.webpackContext, so need to be fixed too

For example, highlight.js has the following in exports of package.json:

{
"exports": {
"./lib/languages/*": {
"require": "./lib/languages/*.js",
"import": "./es/languages/*.js"
}
}
}

I tried to import a language dynamically using the following code in a Vue 3 / TS 4 app:

const langName = ref('')
const message = ref('')
const module = await import(
`highlight.js/lib/languages/${langName.value}`
)
message.value = module.default.name

This leads to the following error:

error in ./src/App.vue?vue&type=script&lang=ts

Module not found: Error: Package path ./lib/languages is not exported from package <path_to_proj>/node_modules/highlight.js (see exports field in <path_to_proj>/node_modules/highlight.js/package.json)

If the current behavior is a bug, please provide the steps to reproduce.

Clone minimum reproduction repo and npm install.

Run the project with npm run serve.

See error.

What is the expected behavior?

Replacing ${langName.value} with a literal value works and imports the file as expected:

const langName = ref('')
const message = ref('')
const module = await import(
`highlight.js/lib/languages/javascript`
)
message.value = module.default.name

Dynamic import should work equally well.

Workarounds

The comment highlightjs/highlight.js#3223 (comment) contains possible workarounds, if that helps to narrow the problem.

Other relevant information:

webpack version: 5

Node.js version: 14

Operating System: mac OS

Additional tools: TypeScript 4, Vue 3, Babel 7