fix(bundling): correctly handle .cjs.js .mjs.js in rollup for type definitions (#29366)
…le extensions for type definitions. Updated the Rollup plugin's logic for generating type definition files to ensure compatibility with additional file extensions, including .cjs.js and .mjs.js. This change improves the handling of entry points and ensures that corresponding .d.ts files are correctly named and emitted in all supported scenarios. Added a comprehensive test case to validate the new behavior. closed #29308 <!-- 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 --> ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes # --------- Co-authored-by: Colum Ferry <cferry09@gmail.com>
This commit is contained in:
parent
ec0eda513d
commit
8ddd697a07
@ -168,8 +168,8 @@ describe('release publishable libraries in workspace with ts solution setup', ()
|
|||||||
📦 @proj/{project-name}@0.0.3
|
📦 @proj/{project-name}@0.0.3
|
||||||
=== Tarball Contents ===
|
=== Tarball Contents ===
|
||||||
XXB README.md
|
XXB README.md
|
||||||
|
XXB dist/index.d.ts
|
||||||
XXB dist/index.esm.css
|
XXB dist/index.esm.css
|
||||||
XXB dist/index.esm.d.ts
|
|
||||||
XXB dist/index.esm.js
|
XXB dist/index.esm.js
|
||||||
XXX.XXX kb dist/README.md
|
XXX.XXX kb dist/README.md
|
||||||
XXB dist/src/index.d.ts
|
XXB dist/src/index.d.ts
|
||||||
|
|||||||
@ -170,8 +170,8 @@ describe('release publishable libraries', () => {
|
|||||||
📦 @proj/{project-name}@0.0.3
|
📦 @proj/{project-name}@0.0.3
|
||||||
=== Tarball Contents ===
|
=== Tarball Contents ===
|
||||||
XXX.XXX kb README.md
|
XXX.XXX kb README.md
|
||||||
|
XXB index.d.ts
|
||||||
XXB index.esm.css
|
XXB index.esm.css
|
||||||
XXB index.esm.d.ts
|
|
||||||
XXB index.esm.js
|
XXB index.esm.js
|
||||||
XXXB package.json
|
XXXB package.json
|
||||||
XXB src/index.d.ts
|
XXB src/index.d.ts
|
||||||
|
|||||||
@ -41,13 +41,13 @@ describe('Rollup Plugin', () => {
|
|||||||
);
|
);
|
||||||
rmDist();
|
rmDist();
|
||||||
runCLI(`build ${myPkg} --format=cjs,esm --generateExportsField`);
|
runCLI(`build ${myPkg} --format=cjs,esm --generateExportsField`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.d.ts`);
|
checkFilesExist(`dist/libs/${myPkg}/index.d.ts`);
|
||||||
expect(readJson(`dist/libs/${myPkg}/package.json`).exports).toEqual({
|
expect(readJson(`dist/libs/${myPkg}/package.json`).exports).toEqual({
|
||||||
'.': {
|
'.': {
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
import: './index.cjs.mjs',
|
import: './index.cjs.mjs',
|
||||||
default: './index.cjs.js',
|
default: './index.cjs.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
},
|
},
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
});
|
});
|
||||||
@ -106,7 +106,7 @@ describe('Rollup Plugin', () => {
|
|||||||
|
|
||||||
checkFilesExist(`dist/libs/${myPkg}/index.esm.js`);
|
checkFilesExist(`dist/libs/${myPkg}/index.esm.js`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.js`);
|
checkFilesExist(`dist/libs/${myPkg}/index.cjs.js`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.d.ts`);
|
checkFilesExist(`dist/libs/${myPkg}/index.d.ts`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/foo.esm.js`);
|
checkFilesExist(`dist/libs/${myPkg}/foo.esm.js`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/foo.cjs.js`);
|
checkFilesExist(`dist/libs/${myPkg}/foo.cjs.js`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/bar.esm.js`);
|
checkFilesExist(`dist/libs/${myPkg}/bar.esm.js`);
|
||||||
@ -117,19 +117,19 @@ describe('Rollup Plugin', () => {
|
|||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
import: './index.cjs.mjs',
|
import: './index.cjs.mjs',
|
||||||
default: './index.cjs.js',
|
default: './index.cjs.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
},
|
},
|
||||||
'./bar': {
|
'./bar': {
|
||||||
module: './bar.esm.js',
|
module: './bar.esm.js',
|
||||||
import: './bar.cjs.mjs',
|
import: './bar.cjs.mjs',
|
||||||
default: './bar.cjs.js',
|
default: './bar.cjs.js',
|
||||||
types: './bar.esm.d.ts',
|
types: './bar.d.ts',
|
||||||
},
|
},
|
||||||
'./foo': {
|
'./foo': {
|
||||||
module: './foo.esm.js',
|
module: './foo.esm.js',
|
||||||
import: './foo.cjs.mjs',
|
import: './foo.cjs.mjs',
|
||||||
default: './foo.cjs.js',
|
default: './foo.cjs.js',
|
||||||
types: './foo.esm.d.ts',
|
types: './foo.d.ts',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -43,13 +43,13 @@ describe('Rollup Plugin', () => {
|
|||||||
);
|
);
|
||||||
rmDist();
|
rmDist();
|
||||||
runCLI(`build ${myPkg}`);
|
runCLI(`build ${myPkg}`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.d.ts`);
|
checkFilesExist(`dist/libs/${myPkg}/index.d.ts`);
|
||||||
expect(readJson(`dist/libs/${myPkg}/package.json`).exports).toEqual({
|
expect(readJson(`dist/libs/${myPkg}/package.json`).exports).toEqual({
|
||||||
'.': {
|
'.': {
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
import: './index.cjs.mjs',
|
import: './index.cjs.mjs',
|
||||||
default: './index.cjs.js',
|
default: './index.cjs.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
},
|
},
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
});
|
});
|
||||||
@ -139,7 +139,7 @@ describe('Rollup Plugin', () => {
|
|||||||
checkFilesExist(`dist/libs/${myPkg}/index.esm.js.map`);
|
checkFilesExist(`dist/libs/${myPkg}/index.esm.js.map`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.js`);
|
checkFilesExist(`dist/libs/${myPkg}/index.cjs.js`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.js.map`);
|
checkFilesExist(`dist/libs/${myPkg}/index.cjs.js.map`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.d.ts`);
|
checkFilesExist(`dist/libs/${myPkg}/index.d.ts`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/foo.esm.js`);
|
checkFilesExist(`dist/libs/${myPkg}/foo.esm.js`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/foo.esm.js.map`);
|
checkFilesExist(`dist/libs/${myPkg}/foo.esm.js.map`);
|
||||||
checkFilesExist(`dist/libs/${myPkg}/foo.cjs.js`);
|
checkFilesExist(`dist/libs/${myPkg}/foo.cjs.js`);
|
||||||
@ -154,19 +154,19 @@ describe('Rollup Plugin', () => {
|
|||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
import: './index.cjs.mjs',
|
import: './index.cjs.mjs',
|
||||||
default: './index.cjs.js',
|
default: './index.cjs.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
},
|
},
|
||||||
'./bar': {
|
'./bar': {
|
||||||
module: './bar.esm.js',
|
module: './bar.esm.js',
|
||||||
import: './bar.cjs.mjs',
|
import: './bar.cjs.mjs',
|
||||||
default: './bar.cjs.js',
|
default: './bar.cjs.js',
|
||||||
types: './bar.esm.d.ts',
|
types: './bar.d.ts',
|
||||||
},
|
},
|
||||||
'./foo': {
|
'./foo': {
|
||||||
module: './foo.esm.js',
|
module: './foo.esm.js',
|
||||||
import: './foo.cjs.mjs',
|
import: './foo.cjs.mjs',
|
||||||
default: './foo.cjs.js',
|
default: './foo.cjs.js',
|
||||||
types: './foo.esm.d.ts',
|
types: './foo.d.ts',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
71
packages/js/src/plugins/rollup/type-definitions.spec.ts
Normal file
71
packages/js/src/plugins/rollup/type-definitions.spec.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { typeDefinitions } from './type-definitions';
|
||||||
|
describe('typeDefinitions', () => {
|
||||||
|
it('should emit correct .d.ts filenames for various file formats', () => {
|
||||||
|
const mockBundle = {
|
||||||
|
'index.js': {
|
||||||
|
type: 'chunk',
|
||||||
|
isEntry: true,
|
||||||
|
fileName: 'index.js',
|
||||||
|
facadeModuleId: '/project/src/index.ts',
|
||||||
|
exports: ['default', 'namedExport1', 'namedExport2'],
|
||||||
|
},
|
||||||
|
'index1.js': {
|
||||||
|
type: 'chunk',
|
||||||
|
isEntry: true,
|
||||||
|
fileName: 'index.cjs',
|
||||||
|
facadeModuleId: '/project/src/index.ts',
|
||||||
|
exports: ['default', 'namedExport1', 'namedExport2'],
|
||||||
|
},
|
||||||
|
'index2.js': {
|
||||||
|
type: 'chunk',
|
||||||
|
isEntry: true,
|
||||||
|
fileName: 'index.mjs',
|
||||||
|
facadeModuleId: '/project/src/index.ts',
|
||||||
|
exports: ['default', 'namedExport1', 'namedExport2'],
|
||||||
|
},
|
||||||
|
'index3.js': {
|
||||||
|
type: 'chunk',
|
||||||
|
isEntry: true,
|
||||||
|
fileName: 'index.cjs.js',
|
||||||
|
facadeModuleId: '/project/src/index.ts',
|
||||||
|
exports: ['default', 'namedExport1', 'namedExport2'],
|
||||||
|
},
|
||||||
|
'index4.js': {
|
||||||
|
type: 'chunk',
|
||||||
|
isEntry: true,
|
||||||
|
fileName: 'index.mjs.js',
|
||||||
|
facadeModuleId: '/project/src/index.ts',
|
||||||
|
exports: ['default', 'namedExport1', 'namedExport2'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockOpts = {}; // Can be left empty for this scenario
|
||||||
|
|
||||||
|
const mockEmitFile = jest.fn();
|
||||||
|
|
||||||
|
const plugin = typeDefinitions({ projectRoot: '/project' });
|
||||||
|
|
||||||
|
// Simulate the `this` context of a Rollup plugin
|
||||||
|
const mockContext = {
|
||||||
|
emitFile: mockEmitFile,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run the plugin's `generateBundle` function
|
||||||
|
(async function testPlugin() {
|
||||||
|
await plugin.generateBundle.call(mockContext, mockOpts, mockBundle);
|
||||||
|
|
||||||
|
// Verify the correct .d.ts filenames are generated for different file formats
|
||||||
|
const expectedFileNames = [
|
||||||
|
'index.d.ts', // from index.js
|
||||||
|
'index.d.ts', // from index.cjs
|
||||||
|
'index.d.ts', // from index.mjs
|
||||||
|
'index.d.ts', // from index.cjs.js
|
||||||
|
'index.d.ts', // from index.mjs.js
|
||||||
|
];
|
||||||
|
|
||||||
|
mockEmitFile.mock.calls.forEach(([{ fileName }], index) => {
|
||||||
|
expect(fileName).toBe(expectedFileNames[index]);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -38,7 +38,14 @@ export function typeDefinitions(options: { projectRoot: string }) {
|
|||||||
/\.[cm]?[jt]sx?$/,
|
/\.[cm]?[jt]sx?$/,
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
const dtsFileName = file.fileName.replace(/\.[cm]?js$/, '.d.ts');
|
|
||||||
|
// Replace various JavaScript file extensions (e.g., .js, .cjs, .mjs, .cjs.js, .mjs.js) with .d.ts for generating type definition file names.
|
||||||
|
// This regex matches the pattern used in packages/rollup/src/plugins/package-json/update-package-json.ts
|
||||||
|
const dtsFileName = file.fileName.replace(
|
||||||
|
/(\.cjs|\.mjs|\.esm\.js|\.cjs\.js|\.mjs\.js|\.js)$/,
|
||||||
|
'.d.ts'
|
||||||
|
);
|
||||||
|
|
||||||
const relativeSourceDtsName = JSON.stringify('./' + entrySourceDtsName);
|
const relativeSourceDtsName = JSON.stringify('./' + entrySourceDtsName);
|
||||||
const dtsFileSource = hasDefaultExport
|
const dtsFileSource = hasDefaultExport
|
||||||
? stripIndents`
|
? stripIndents`
|
||||||
|
|||||||
@ -32,13 +32,13 @@ describe('updatePackageJson', () => {
|
|||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
'.': {
|
'.': {
|
||||||
import: './index.esm.js',
|
import: './index.esm.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
main: './index.esm.js',
|
main: './index.esm.js',
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
type: 'module',
|
type: 'module',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
});
|
});
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
@ -63,7 +63,7 @@ describe('updatePackageJson', () => {
|
|||||||
},
|
},
|
||||||
main: './index.cjs.js',
|
main: './index.cjs.js',
|
||||||
type: 'commonjs',
|
type: 'commonjs',
|
||||||
types: './index.cjs.d.ts',
|
types: './index.d.ts',
|
||||||
});
|
});
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
@ -88,12 +88,12 @@ describe('updatePackageJson', () => {
|
|||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
import: './index.cjs.mjs',
|
import: './index.cjs.mjs',
|
||||||
default: './index.cjs.js',
|
default: './index.cjs.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
main: './index.cjs.js',
|
main: './index.cjs.js',
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
});
|
});
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
@ -123,7 +123,7 @@ describe('updatePackageJson', () => {
|
|||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
'.': {
|
'.': {
|
||||||
import: './index.esm.js',
|
import: './index.esm.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
},
|
},
|
||||||
'./foo': {
|
'./foo': {
|
||||||
import: './some/custom/path/foo.esm.js',
|
import: './some/custom/path/foo.esm.js',
|
||||||
@ -133,7 +133,7 @@ describe('updatePackageJson', () => {
|
|||||||
main: './index.esm.js',
|
main: './index.esm.js',
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
type: 'module',
|
type: 'module',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
});
|
});
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
@ -156,7 +156,7 @@ describe('updatePackageJson', () => {
|
|||||||
main: './index.esm.js',
|
main: './index.esm.js',
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
type: 'module',
|
type: 'module',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
});
|
});
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
@ -176,7 +176,7 @@ describe('updatePackageJson', () => {
|
|||||||
expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), {
|
expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), {
|
||||||
main: './index.cjs.js',
|
main: './index.cjs.js',
|
||||||
type: 'commonjs',
|
type: 'commonjs',
|
||||||
types: './index.cjs.d.ts',
|
types: './index.d.ts',
|
||||||
});
|
});
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
@ -196,7 +196,7 @@ describe('updatePackageJson', () => {
|
|||||||
expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), {
|
expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), {
|
||||||
main: './index.cjs.js',
|
main: './index.cjs.js',
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
});
|
});
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
@ -221,7 +221,7 @@ describe('updatePackageJson', () => {
|
|||||||
main: './index.esm.js',
|
main: './index.esm.js',
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
type: 'module',
|
type: 'module',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
exports: {
|
exports: {
|
||||||
'./foo': './foo.esm.js',
|
'./foo': './foo.esm.js',
|
||||||
},
|
},
|
||||||
@ -251,7 +251,7 @@ describe('updatePackageJson', () => {
|
|||||||
expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), {
|
expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), {
|
||||||
main: './index.esm.js',
|
main: './index.esm.js',
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
exports: {
|
exports: {
|
||||||
'./foo': './foo.esm.js',
|
'./foo': './foo.esm.js',
|
||||||
},
|
},
|
||||||
@ -279,7 +279,7 @@ describe('updatePackageJson', () => {
|
|||||||
main: './index.esm.js',
|
main: './index.esm.js',
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
type: 'module',
|
type: 'module',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
exports: {
|
exports: {
|
||||||
'./foo': './foo.esm.js',
|
'./foo': './foo.esm.js',
|
||||||
},
|
},
|
||||||
@ -308,7 +308,7 @@ describe('updatePackageJson', () => {
|
|||||||
main: './index.esm.js',
|
main: './index.esm.js',
|
||||||
module: './index.esm.js',
|
module: './index.esm.js',
|
||||||
type: 'module',
|
type: 'module',
|
||||||
types: './index.esm.d.ts',
|
types: './index.d.ts',
|
||||||
exports: {
|
exports: {
|
||||||
'./foo': './foo.esm.js',
|
'./foo': './foo.esm.js',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export function updatePackageJson(
|
|||||||
},
|
},
|
||||||
packageJson: PackageJson
|
packageJson: PackageJson
|
||||||
) {
|
) {
|
||||||
|
const jsFileRegex = /(\.cjs|\.mjs|\.esm\.js|\.cjs\.js|\.mjs\.js|\.js)$/;
|
||||||
const hasEsmFormat = options.format.includes('esm');
|
const hasEsmFormat = options.format.includes('esm');
|
||||||
const hasCjsFormat = options.format.includes('cjs');
|
const hasCjsFormat = options.format.includes('cjs');
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ export function updatePackageJson(
|
|||||||
// Reserve `module` entry for bundlers to accommodate tree-shaking.
|
// Reserve `module` entry for bundlers to accommodate tree-shaking.
|
||||||
{
|
{
|
||||||
[hasCjsFormat ? 'module' : 'import']: filePath,
|
[hasCjsFormat ? 'module' : 'import']: filePath,
|
||||||
types: filePath.replace(/\.js$/, '.d.ts'),
|
types: filePath.replace(jsFileRegex, '.d.ts'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,9 +111,9 @@ export function updatePackageJson(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (packageJson.module) {
|
if (packageJson.module) {
|
||||||
packageJson.types ??= packageJson.module.replace(/\.js$/, '.d.ts');
|
packageJson.types ??= packageJson.module.replace(jsFileRegex, '.d.ts');
|
||||||
} else {
|
} else {
|
||||||
packageJson.types ??= packageJson.main.replace(/\.js$/, '.d.ts');
|
packageJson.types ??= packageJson.main.replace(jsFileRegex, '.d.ts');
|
||||||
}
|
}
|
||||||
|
|
||||||
writeJsonFile(
|
writeJsonFile(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user