fix(webpack): add extension alias support for handling ESM libs (#30513)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
Currently, if you have a webpack application that uses out
NxWebpackAppPlugin and has a non-buildable lib that has exports with
extension enabled for example:`export * from './lib/lib8446520.js';`.
The app fails to build.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
When using webpack and including libraries that contain extension it
should resolve.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #30492
This commit is contained in:
Nicholas Cunningham 2025-03-28 11:51:20 -06:00 committed by GitHub
parent 90ff03d42d
commit bf8848da95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 58 additions and 1 deletions

View File

@ -1,9 +1,15 @@
import { import {
checkFilesExist,
cleanupProject, cleanupProject,
getPackageManagerCommand,
newProject, newProject,
readFile,
readJson, readJson,
runCLI, runCLI,
runCommand,
uniq, uniq,
updateFile,
updateJson,
} from '@nx/e2e/utils'; } from '@nx/e2e/utils';
describe('React (TS solution)', () => { describe('React (TS solution)', () => {
@ -38,4 +44,47 @@ describe('React (TS solution)', () => {
`Successfully ran target test for project ${lib}` `Successfully ran target test for project ${lib}`
); );
}, 90000); }, 90000);
it('should be able to use Webpack to build apps with an imported lib', async () => {
const appName = uniq('app');
const libName = uniq('lib');
runCLI(
`generate @nx/react:app packages/${appName} --bundler=webpack --no-interactive --skipFormat --linter=eslint --unitTestRunner=none`
);
runCLI(
`generate @nx/js:lib libs/${libName} --bundler=none --no-interactive --unit-test-runner=none --skipFormat --linter=eslint`
);
const mainPath = `packages/${appName}/src/main.tsx`;
updateFile(
mainPath,
`
import {${libName}} from '@${workspaceName}/${libName}';
${readFile(mainPath)}
console.log(${libName}());
`
);
runCLI('sync');
// Add library to package.json to make sure it is linked (not needed for npm package manager)
updateJson(`packages/${appName}/package.json`, (json) => {
return {
...json,
devDependencies: {
...(json.devDependencies || {}),
[`@${workspaceName}/${libName}`]: 'workspace:*',
},
};
});
runCommand(
`cd packages/${appName} && ${getPackageManagerCommand().install}`
);
runCLI(`build ${appName}`);
checkFilesExist(`packages/${appName}/dist/index.html`);
}, 90_000);
}); });

View File

@ -10,7 +10,7 @@ import {
updateFile, updateFile,
} from '@nx/e2e/utils'; } from '@nx/e2e/utils';
describe('Build React applications and libraries with Vite', () => { describe('Build React applications and libraries with Webpack', () => {
beforeAll(() => { beforeAll(() => {
newProject({ newProject({
packages: ['@nx/react'], packages: ['@nx/react'],

View File

@ -26,6 +26,10 @@ const IGNORED_WEBPACK_WARNINGS = [
/could not find any license/i, /could not find any license/i,
]; ];
const extensionAlias = {
'.js': ['.ts', '.js'],
'.mjs': ['.mts', '.mjs'],
};
const extensions = ['.ts', '.tsx', '.mjs', '.js', '.jsx']; const extensions = ['.ts', '.tsx', '.mjs', '.js', '.jsx'];
const mainFields = ['module', 'main']; const mainFields = ['module', 'main'];
@ -356,6 +360,10 @@ function applyNxDependentConfig(
config.resolve = { config.resolve = {
...config.resolve, ...config.resolve,
extensions: [...(config?.resolve?.extensions ?? []), ...extensions], extensions: [...(config?.resolve?.extensions ?? []), ...extensions],
extensionAlias: {
...(config.resolve?.extensionAlias ?? {}),
...extensionAlias,
},
alias: { alias: {
...(config.resolve?.alias ?? {}), ...(config.resolve?.alias ?? {}),
...(options.fileReplacements?.reduce( ...(options.fileReplacements?.reduce(