feat(bundling): extract rollup plugins into withNx function for use with run-commands (#26168)
This PR adds `withNx` function to `@nx/rollup/with-nx` so it can be used
in `rollup.config.js` to replicate what `@nx/rollup:rollup` executor
does without needing to use the executor.
e.g.
```js
// rollup.config.js
const { withNx } = require("@nx/rollup/with-nx");
module.exports = withNx(
{
main: "./src/index.ts",
outputPath: "./dist",
tsConfig: "./tsconfig.lib.json",
compiler: "babel",
external: ["react", "react-dom", "react/jsx-runtime"],
format: ["esm"],
assets: [{ input: ".", output: ".", glob: "README.md" }],
},
{
// Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
// e.g.
// output: { sourcemap: true },
}
);
```
## Notes
1. Existing `@nx/rollup:rollup` continues to encapsulate rollup options
and will not support an isolated mode.
2. Newly created JS and React libs with `--bundler=rollup` will use the
new `withNx` function and explicit `rollup.config.js`.
3. If `NX_ADD_PLUGINS=false` or `useInferencePlugins: false` is set,
then new projects will continue to use the `@nx/rollup:rollup` executor.
This commit is contained in:
parent
c05e4ac268
commit
4e49d527ba
202
e2e/react/src/react-package-legacy.test.ts
Normal file
202
e2e/react/src/react-package-legacy.test.ts
Normal file
@ -0,0 +1,202 @@
|
||||
import {
|
||||
checkFilesDoNotExist,
|
||||
checkFilesExist,
|
||||
cleanupProject,
|
||||
getSize,
|
||||
killPorts,
|
||||
newProject,
|
||||
readFile,
|
||||
readJson,
|
||||
rmDist,
|
||||
runCLI,
|
||||
runCLIAsync,
|
||||
tmpProjPath,
|
||||
uniq,
|
||||
updateFile,
|
||||
updateJson,
|
||||
} from '@nx/e2e/utils';
|
||||
import { names } from '@nx/devkit';
|
||||
import { join } from 'path';
|
||||
|
||||
describe('Build React libraries and apps', () => {
|
||||
/**
|
||||
* Graph:
|
||||
*
|
||||
* childLib
|
||||
* /
|
||||
* app => parentLib =>
|
||||
* \
|
||||
* childLib2
|
||||
*
|
||||
*/
|
||||
let app: string;
|
||||
let parentLib: string;
|
||||
let childLib: string;
|
||||
let childLib2: string;
|
||||
|
||||
let proj: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
process.env.NX_ADD_PLUGINS = 'false';
|
||||
app = uniq('app');
|
||||
parentLib = uniq('parentlib');
|
||||
childLib = uniq('childlib');
|
||||
childLib2 = uniq('childlib2');
|
||||
|
||||
proj = newProject({ packages: ['@nx/react'] });
|
||||
|
||||
// create dependencies by importing
|
||||
const createDep = (parent, children: string[]) => {
|
||||
updateFile(
|
||||
`libs/${parent}/src/index.ts`,
|
||||
`
|
||||
export * from './lib/${parent}';
|
||||
|
||||
${children
|
||||
.map(
|
||||
(entry) =>
|
||||
`import { ${
|
||||
names(entry).className
|
||||
} } from '@${proj}/${entry}'; console.log(${
|
||||
names(entry).className
|
||||
});`
|
||||
)
|
||||
.join('\n')}
|
||||
`
|
||||
);
|
||||
};
|
||||
|
||||
runCLI(`generate @nx/react:app ${app} `);
|
||||
updateJson('nx.json', (json) => ({
|
||||
...json,
|
||||
generators: {
|
||||
...json.generators,
|
||||
'@nx/react': {
|
||||
library: {
|
||||
unitTestRunner: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
// generate buildable libs
|
||||
runCLI(
|
||||
`generate @nx/react:library ${parentLib} --bundler=rollup --importPath=@${proj}/${parentLib} --no-interactive --unitTestRunner=jest --skipFormat`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/react:library ${childLib} --bundler=rollup --importPath=@${proj}/${childLib} --no-interactive --unitTestRunner=jest --skipFormat`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/react:library ${childLib2} --bundler=rollup --importPath=@${proj}/${childLib2} --no-interactive --unitTestRunner=jest --skipFormat`
|
||||
);
|
||||
|
||||
createDep(parentLib, [childLib, childLib2]);
|
||||
|
||||
updateFile(
|
||||
`apps/${app}/src/main.tsx`,
|
||||
`
|
||||
import {${names(parentLib).className}} from "@${proj}/${parentLib}";
|
||||
console.log(${names(parentLib).className});
|
||||
`
|
||||
);
|
||||
|
||||
// Add assets to child lib
|
||||
updateJson(join('libs', childLib, 'project.json'), (json) => {
|
||||
json.targets.build.options.assets = [`libs/${childLib}/src/assets`];
|
||||
return json;
|
||||
});
|
||||
updateFile(`libs/${childLib}/src/assets/hello.txt`, 'Hello World!');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
killPorts();
|
||||
cleanupProject();
|
||||
delete process.env.NX_ADD_PLUGINS;
|
||||
});
|
||||
|
||||
describe('Buildable libraries', () => {
|
||||
it('should build libraries with and without dependencies', () => {
|
||||
/*
|
||||
* 1. Without dependencies
|
||||
*/
|
||||
runCLI(`build ${childLib}`);
|
||||
runCLI(`build ${childLib2}`);
|
||||
|
||||
checkFilesExist(`dist/libs/${childLib}/index.esm.js`);
|
||||
|
||||
checkFilesExist(`dist/libs/${childLib2}/index.esm.js`);
|
||||
|
||||
checkFilesExist(`dist/libs/${childLib}/assets/hello.txt`);
|
||||
checkFilesExist(`dist/libs/${childLib2}/README.md`);
|
||||
|
||||
/*
|
||||
* 2. With dependencies without existing dist
|
||||
*/
|
||||
rmDist();
|
||||
|
||||
runCLI(`build ${parentLib} --skip-nx-cache`);
|
||||
|
||||
checkFilesExist(`dist/libs/${parentLib}/index.esm.js`);
|
||||
checkFilesExist(`dist/libs/${childLib}/index.esm.js`);
|
||||
checkFilesExist(`dist/libs/${childLib2}/index.esm.js`);
|
||||
|
||||
expect(readFile(`dist/libs/${childLib}/index.esm.js`)).not.toContain(
|
||||
'react/jsx-dev-runtime'
|
||||
);
|
||||
expect(readFile(`dist/libs/${childLib}/index.esm.js`)).toContain(
|
||||
'react/jsx-runtime'
|
||||
);
|
||||
});
|
||||
|
||||
it('should support --format option', () => {
|
||||
updateFile(
|
||||
`libs/${childLib}/src/index.ts`,
|
||||
(s) => `${s}
|
||||
export async function f() { return 'a'; }
|
||||
export async function g() { return 'b'; }
|
||||
export async function h() { return 'c'; }
|
||||
`
|
||||
);
|
||||
|
||||
runCLI(`build ${childLib} --format cjs,esm`);
|
||||
|
||||
checkFilesExist(`dist/libs/${childLib}/index.cjs.js`);
|
||||
checkFilesExist(`dist/libs/${childLib}/index.esm.js`);
|
||||
|
||||
const cjsPackageSize = getSize(
|
||||
tmpProjPath(`dist/libs/${childLib}/index.cjs.js`)
|
||||
);
|
||||
const esmPackageSize = getSize(
|
||||
tmpProjPath(`dist/libs/${childLib}/index.esm.js`)
|
||||
);
|
||||
|
||||
// This is a loose requirement that ESM should be smaller than CJS output.
|
||||
expect(esmPackageSize).toBeLessThanOrEqual(cjsPackageSize);
|
||||
});
|
||||
|
||||
it('should build an app composed out of buildable libs', () => {
|
||||
const buildFromSource = runCLI(
|
||||
`build ${app} --buildLibsFromSource=false`
|
||||
);
|
||||
expect(buildFromSource).toContain('Successfully ran target build');
|
||||
checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`);
|
||||
}, 1000000);
|
||||
|
||||
it('should not create a dist folder if there is an error', async () => {
|
||||
const libName = uniq('lib');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/react:lib ${libName} --bundler=rollup --importPath=@${proj}/${libName} --no-interactive --unitTestRunner=jest`
|
||||
);
|
||||
|
||||
const mainPath = `libs/${libName}/src/lib/${libName}.tsx`;
|
||||
updateFile(mainPath, `${readFile(mainPath)}\n console.log(a);`); // should error - "a" will be undefined
|
||||
|
||||
await expect(runCLIAsync(`build ${libName}`)).rejects.toThrow(
|
||||
/Bundle failed/
|
||||
);
|
||||
expect(() => {
|
||||
checkFilesExist(`dist/libs/${libName}/package.json`);
|
||||
}).toThrow();
|
||||
}, 250000);
|
||||
});
|
||||
});
|
||||
@ -1,16 +1,12 @@
|
||||
import {
|
||||
checkFilesDoNotExist,
|
||||
checkFilesExist,
|
||||
cleanupProject,
|
||||
getSize,
|
||||
killPorts,
|
||||
newProject,
|
||||
readFile,
|
||||
readJson,
|
||||
rmDist,
|
||||
runCLI,
|
||||
runCLIAsync,
|
||||
tmpProjPath,
|
||||
uniq,
|
||||
updateFile,
|
||||
updateJson,
|
||||
@ -37,7 +33,6 @@ describe('Build React libraries and apps', () => {
|
||||
let proj: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
process.env.NX_ADD_PLUGINS = 'false';
|
||||
app = uniq('app');
|
||||
parentLib = uniq('parentlib');
|
||||
childLib = uniq('childlib');
|
||||
@ -100,17 +95,28 @@ describe('Build React libraries and apps', () => {
|
||||
);
|
||||
|
||||
// Add assets to child lib
|
||||
updateJson(join('libs', childLib, 'project.json'), (json) => {
|
||||
json.targets.build.options.assets = [`libs/${childLib}/src/assets`];
|
||||
return json;
|
||||
});
|
||||
updateFile(
|
||||
join('libs', childLib, 'rollup.config.js'),
|
||||
`const { withNx } = require('@nx/rollup/with-nx');
|
||||
module.exports = withNx(
|
||||
{
|
||||
main: './src/index.ts',
|
||||
outputPath: '../../dist/libs/${childLib}',
|
||||
tsConfig: './tsconfig.lib.json',
|
||||
compiler: 'babel',
|
||||
external: ['react', 'react-dom', 'react/jsx-runtime'],
|
||||
format: ['esm'],
|
||||
assets: ['./src/assets'],
|
||||
}
|
||||
);
|
||||
`
|
||||
);
|
||||
updateFile(`libs/${childLib}/src/assets/hello.txt`, 'Hello World!');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
killPorts();
|
||||
cleanupProject();
|
||||
delete process.env.NX_ADD_PLUGINS;
|
||||
});
|
||||
|
||||
describe('Buildable libraries', () => {
|
||||
@ -147,32 +153,6 @@ describe('Build React libraries and apps', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should support --format option', () => {
|
||||
updateFile(
|
||||
`libs/${childLib}/src/index.ts`,
|
||||
(s) => `${s}
|
||||
export async function f() { return 'a'; }
|
||||
export async function g() { return 'b'; }
|
||||
export async function h() { return 'c'; }
|
||||
`
|
||||
);
|
||||
|
||||
runCLI(`build ${childLib} --format cjs,esm`);
|
||||
|
||||
checkFilesExist(`dist/libs/${childLib}/index.cjs.js`);
|
||||
checkFilesExist(`dist/libs/${childLib}/index.esm.js`);
|
||||
|
||||
const cjsPackageSize = getSize(
|
||||
tmpProjPath(`dist/libs/${childLib}/index.cjs.js`)
|
||||
);
|
||||
const esmPackageSize = getSize(
|
||||
tmpProjPath(`dist/libs/${childLib}/index.esm.js`)
|
||||
);
|
||||
|
||||
// This is a loose requirement that ESM should be smaller than CJS output.
|
||||
expect(esmPackageSize).toBeLessThanOrEqual(cjsPackageSize);
|
||||
});
|
||||
|
||||
it('should preserve the tsconfig target set by user', () => {
|
||||
// Setup
|
||||
const myLib = uniq('my-lib');
|
||||
@ -224,14 +204,6 @@ export async function h() { return 'c'; }
|
||||
expect(content).toContain('function __generator(thisArg, body) {');
|
||||
});
|
||||
|
||||
it('should build an app composed out of buildable libs', () => {
|
||||
const buildFromSource = runCLI(
|
||||
`build ${app} --buildLibsFromSource=false`
|
||||
);
|
||||
expect(buildFromSource).toContain('Successfully ran target build');
|
||||
checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`);
|
||||
}, 1000000);
|
||||
|
||||
it('should not create a dist folder if there is an error', async () => {
|
||||
const libName = uniq('lib');
|
||||
|
||||
@ -243,7 +215,7 @@ export async function h() { return 'c'; }
|
||||
updateFile(mainPath, `${readFile(mainPath)}\n console.log(a);`); // should error - "a" will be undefined
|
||||
|
||||
await expect(runCLIAsync(`build ${libName}`)).rejects.toThrow(
|
||||
/Bundle failed/
|
||||
/Command failed/
|
||||
);
|
||||
expect(() => {
|
||||
checkFilesExist(`dist/libs/${libName}/package.json`);
|
||||
|
||||
201
e2e/rollup/src/rollup-legacy.test.ts
Normal file
201
e2e/rollup/src/rollup-legacy.test.ts
Normal file
@ -0,0 +1,201 @@
|
||||
import {
|
||||
checkFilesExist,
|
||||
cleanupProject,
|
||||
newProject,
|
||||
packageInstall,
|
||||
readJson,
|
||||
rmDist,
|
||||
runCLI,
|
||||
runCommand,
|
||||
uniq,
|
||||
updateFile,
|
||||
updateJson,
|
||||
} from '@nx/e2e/utils';
|
||||
import { join } from 'path';
|
||||
|
||||
describe('Rollup Plugin', () => {
|
||||
let originalAddPluginsEnv: string | undefined;
|
||||
|
||||
beforeAll(() => {
|
||||
originalAddPluginsEnv = process.env.NX_ADD_PLUGINS;
|
||||
process.env.NX_ADD_PLUGINS = 'false';
|
||||
newProject({ packages: ['@nx/rollup', '@nx/js'] });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
process.env.NX_ADD_PLUGINS = originalAddPluginsEnv;
|
||||
cleanupProject();
|
||||
});
|
||||
|
||||
it('should be able to setup project to build node programs with rollup and different compilers', async () => {
|
||||
const myPkg = uniq('my-pkg');
|
||||
runCLI(`generate @nx/js:lib ${myPkg} --bundler=none`);
|
||||
updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`);
|
||||
|
||||
// babel (default)
|
||||
runCLI(
|
||||
`generate @nx/rollup:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts`
|
||||
);
|
||||
rmDist();
|
||||
runCLI(`build ${myPkg} --format=cjs,esm --generateExportsField`);
|
||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.d.ts`);
|
||||
expect(readJson(`dist/libs/${myPkg}/package.json`).exports).toEqual({
|
||||
'.': {
|
||||
module: './index.esm.js',
|
||||
import: './index.cjs.mjs',
|
||||
default: './index.cjs.js',
|
||||
},
|
||||
'./package.json': './package.json',
|
||||
});
|
||||
let output = runCommand(`node dist/libs/${myPkg}/index.cjs.js`);
|
||||
expect(output).toMatch(/Hello/);
|
||||
|
||||
updateJson(join('libs', myPkg, 'project.json'), (config) => {
|
||||
delete config.targets.build;
|
||||
return config;
|
||||
});
|
||||
|
||||
// swc
|
||||
runCLI(
|
||||
`generate @nx/rollup:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=swc`
|
||||
);
|
||||
rmDist();
|
||||
runCLI(`build ${myPkg} --format=cjs,esm --generateExportsField`);
|
||||
output = runCommand(`node dist/libs/${myPkg}/index.cjs.js`);
|
||||
expect(output).toMatch(/Hello/);
|
||||
|
||||
updateJson(join('libs', myPkg, 'project.json'), (config) => {
|
||||
delete config.targets.build;
|
||||
return config;
|
||||
});
|
||||
|
||||
// tsc
|
||||
runCLI(
|
||||
`generate @nx/rollup:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=tsc`
|
||||
);
|
||||
rmDist();
|
||||
runCLI(`build ${myPkg} --format=cjs,esm --generateExportsField`);
|
||||
output = runCommand(`node dist/libs/${myPkg}/index.cjs.js`);
|
||||
expect(output).toMatch(/Hello/);
|
||||
}, 500000);
|
||||
|
||||
it('should support additional entry-points', async () => {
|
||||
const myPkg = uniq('my-pkg');
|
||||
runCLI(`generate @nx/js:lib ${myPkg} --bundler=none`);
|
||||
runCLI(
|
||||
`generate @nx/rollup:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=tsc`
|
||||
);
|
||||
updateJson(join('libs', myPkg, 'project.json'), (config) => {
|
||||
config.targets.build.options.format = ['cjs', 'esm'];
|
||||
config.targets.build.options.generateExportsField = true;
|
||||
config.targets.build.options.additionalEntryPoints = [
|
||||
`libs/${myPkg}/src/{foo,bar}.ts`,
|
||||
];
|
||||
return config;
|
||||
});
|
||||
updateFile(`libs/${myPkg}/src/foo.ts`, `export const foo = 'foo';`);
|
||||
updateFile(`libs/${myPkg}/src/bar.ts`, `export const bar = 'bar';`);
|
||||
|
||||
runCLI(`build ${myPkg}`);
|
||||
|
||||
checkFilesExist(`dist/libs/${myPkg}/index.esm.js`);
|
||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.js`);
|
||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.d.ts`);
|
||||
checkFilesExist(`dist/libs/${myPkg}/foo.esm.js`);
|
||||
checkFilesExist(`dist/libs/${myPkg}/foo.cjs.js`);
|
||||
checkFilesExist(`dist/libs/${myPkg}/bar.esm.js`);
|
||||
checkFilesExist(`dist/libs/${myPkg}/bar.cjs.js`);
|
||||
expect(readJson(`dist/libs/${myPkg}/package.json`).exports).toEqual({
|
||||
'./package.json': './package.json',
|
||||
'.': {
|
||||
module: './index.esm.js',
|
||||
import: './index.cjs.mjs',
|
||||
default: './index.cjs.js',
|
||||
},
|
||||
'./bar': {
|
||||
module: './bar.esm.js',
|
||||
import: './bar.cjs.mjs',
|
||||
default: './bar.cjs.js',
|
||||
},
|
||||
'./foo': {
|
||||
module: './foo.esm.js',
|
||||
import: './foo.cjs.mjs',
|
||||
default: './foo.cjs.js',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to build libs generated with @nx/js:lib --bundler rollup', () => {
|
||||
const jsLib = uniq('jslib');
|
||||
runCLI(`generate @nx/js:lib ${jsLib} --bundler rollup`);
|
||||
expect(() => runCLI(`build ${jsLib}`)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should be able to build libs generated with @nx/js:lib --bundler rollup with a custom rollup.config.{cjs|mjs}', () => {
|
||||
const jsLib = uniq('jslib');
|
||||
runCLI(`generate @nx/js:lib ${jsLib} --bundler rollup`);
|
||||
updateFile(
|
||||
`libs/${jsLib}/rollup.config.cjs`,
|
||||
`module.exports = {
|
||||
output: {
|
||||
format: "cjs",
|
||||
dir: "dist/test",
|
||||
name: "Mylib",
|
||||
entryFileNames: "[name].cjs.js",
|
||||
chunkFileNames: "[name].cjs.js"
|
||||
}
|
||||
}`
|
||||
);
|
||||
updateJson(join('libs', jsLib, 'project.json'), (config) => {
|
||||
config.targets.build.options.rollupConfig = `libs/${jsLib}/rollup.config.cjs`;
|
||||
return config;
|
||||
});
|
||||
expect(() => runCLI(`build ${jsLib}`)).not.toThrow();
|
||||
checkFilesExist(`dist/test/index.cjs.js`);
|
||||
|
||||
updateFile(
|
||||
`libs/${jsLib}/rollup.config.mjs`,
|
||||
`export default {
|
||||
output: {
|
||||
format: "es",
|
||||
dir: "dist/test",
|
||||
name: "Mylib",
|
||||
entryFileNames: "[name].mjs.js",
|
||||
chunkFileNames: "[name].mjs.js"
|
||||
}
|
||||
}`
|
||||
);
|
||||
updateJson(join('libs', jsLib, 'project.json'), (config) => {
|
||||
config.targets.build.options.rollupConfig = `libs/${jsLib}/rollup.config.mjs`;
|
||||
return config;
|
||||
});
|
||||
expect(() => runCLI(`build ${jsLib}`)).not.toThrow();
|
||||
checkFilesExist(`dist/test/index.mjs.js`);
|
||||
});
|
||||
|
||||
it('should support array config from rollup.config.js', () => {
|
||||
const jsLib = uniq('jslib');
|
||||
runCLI(`generate @nx/js:lib ${jsLib} --bundler rollup --verbose`);
|
||||
updateFile(
|
||||
`libs/${jsLib}/rollup.config.js`,
|
||||
`module.exports = (config) => [{
|
||||
...config,
|
||||
output: {
|
||||
format: "esm",
|
||||
dir: "dist/test",
|
||||
name: "Mylib",
|
||||
entryFileNames: "[name].js",
|
||||
chunkFileNames: "[name].js"
|
||||
}
|
||||
}]`
|
||||
);
|
||||
updateJson(join('libs', jsLib, 'project.json'), (config) => {
|
||||
config.targets.build.options.rollupConfig = `libs/${jsLib}/rollup.config.js`;
|
||||
return config;
|
||||
});
|
||||
|
||||
expect(() => runCLI(`build ${jsLib} --format=esm`)).not.toThrow();
|
||||
|
||||
checkFilesExist(`dist/test/index.js`);
|
||||
});
|
||||
});
|
||||
@ -9,9 +9,7 @@ import {
|
||||
runCommand,
|
||||
uniq,
|
||||
updateFile,
|
||||
updateJson,
|
||||
} from '@nx/e2e/utils';
|
||||
import { join } from 'path';
|
||||
|
||||
describe('Rollup Plugin', () => {
|
||||
beforeAll(() => newProject({ packages: ['@nx/rollup', '@nx/js'] }));
|
||||
@ -19,15 +17,30 @@ describe('Rollup Plugin', () => {
|
||||
|
||||
it('should be able to setup project to build node programs with rollup and different compilers', async () => {
|
||||
const myPkg = uniq('my-pkg');
|
||||
runCLI(`generate @nx/js:lib ${myPkg} --bundler=none`);
|
||||
runCLI(`generate @nx/js:lib ${myPkg} --bundler=rollup`);
|
||||
updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`);
|
||||
|
||||
// babel (default)
|
||||
runCLI(
|
||||
`generate @nx/rollup:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts`
|
||||
`generate @nx/rollup:configuration ${myPkg} --tsConfig=./tsconfig.lib.json --main=./src/index.ts`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${myPkg}/rollup.config.js`,
|
||||
`
|
||||
const { withNx } = require('@nx/rollup/with-nx');
|
||||
module.exports = withNx({
|
||||
outputPath: '../../dist/libs/${myPkg}',
|
||||
main: './src/index.ts',
|
||||
tsConfig: './tsconfig.lib.json',
|
||||
compiler: 'babel',
|
||||
generateExportsField: true,
|
||||
additionalEntryPoints: ['./src/{foo,bar}.ts'],
|
||||
format: ['cjs', 'esm']
|
||||
});
|
||||
`
|
||||
);
|
||||
rmDist();
|
||||
runCLI(`build ${myPkg} --format=cjs,esm --generateExportsField`);
|
||||
runCLI(`build ${myPkg}`);
|
||||
checkFilesExist(`dist/libs/${myPkg}/index.cjs.d.ts`);
|
||||
expect(readJson(`dist/libs/${myPkg}/package.json`).exports).toEqual({
|
||||
'.': {
|
||||
@ -40,31 +53,51 @@ describe('Rollup Plugin', () => {
|
||||
let output = runCommand(`node dist/libs/${myPkg}/index.cjs.js`);
|
||||
expect(output).toMatch(/Hello/);
|
||||
|
||||
updateJson(join('libs', myPkg, 'project.json'), (config) => {
|
||||
delete config.targets.build;
|
||||
return config;
|
||||
});
|
||||
|
||||
// swc
|
||||
runCLI(
|
||||
`generate @nx/rollup:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=swc`
|
||||
`generate @nx/rollup:configuration ${myPkg} --tsConfig=./tsconfig.lib.json --main=./src/index.ts --compiler=swc`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${myPkg}/rollup.config.js`,
|
||||
`
|
||||
const { withNx } = require('@nx/rollup/with-nx');
|
||||
module.exports = withNx({
|
||||
outputPath: '../../dist/libs/${myPkg}',
|
||||
main: './src/index.ts',
|
||||
tsConfig: './tsconfig.lib.json',
|
||||
compiler: 'swc',
|
||||
generateExportsField: true,
|
||||
additionalEntryPoints: ['./src/{foo,bar}.ts'],
|
||||
format: ['cjs', 'esm']
|
||||
});
|
||||
`
|
||||
);
|
||||
rmDist();
|
||||
runCLI(`build ${myPkg} --format=cjs,esm --generateExportsField`);
|
||||
runCLI(`build ${myPkg}`);
|
||||
output = runCommand(`node dist/libs/${myPkg}/index.cjs.js`);
|
||||
expect(output).toMatch(/Hello/);
|
||||
|
||||
updateJson(join('libs', myPkg, 'project.json'), (config) => {
|
||||
delete config.targets.build;
|
||||
return config;
|
||||
});
|
||||
|
||||
// tsc
|
||||
runCLI(
|
||||
`generate @nx/rollup:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=tsc`
|
||||
`generate @nx/rollup:configuration ${myPkg} --tsConfig=./tsconfig.lib.json --main=./src/index.ts --compiler=tsc`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${myPkg}/rollup.config.js`,
|
||||
`
|
||||
const { withNx } = require('@nx/rollup/with-nx');
|
||||
module.exports = withNx({
|
||||
outputPath: '../../dist/libs/${myPkg}',
|
||||
main: './src/index.ts',
|
||||
tsConfig: './tsconfig.lib.json',
|
||||
compiler: 'tsc',
|
||||
generateExportsField: true,
|
||||
additionalEntryPoints: ['./src/{foo,bar}.ts'],
|
||||
format: ['cjs', 'esm']
|
||||
});
|
||||
`
|
||||
);
|
||||
rmDist();
|
||||
runCLI(`build ${myPkg} --format=cjs,esm --generateExportsField`);
|
||||
runCLI(`build ${myPkg}`);
|
||||
output = runCommand(`node dist/libs/${myPkg}/index.cjs.js`);
|
||||
expect(output).toMatch(/Hello/);
|
||||
}, 500000);
|
||||
@ -73,16 +106,24 @@ describe('Rollup Plugin', () => {
|
||||
const myPkg = uniq('my-pkg');
|
||||
runCLI(`generate @nx/js:lib ${myPkg} --bundler=none`);
|
||||
runCLI(
|
||||
`generate @nx/rollup:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=tsc`
|
||||
`generate @nx/rollup:configuration ${myPkg} --tsConfig=./tsconfig.lib.json --main=./src/index.ts --compiler=tsc`
|
||||
);
|
||||
updateJson(join('libs', myPkg, 'project.json'), (config) => {
|
||||
config.targets.build.options.format = ['cjs', 'esm'];
|
||||
config.targets.build.options.generateExportsField = true;
|
||||
config.targets.build.options.additionalEntryPoints = [
|
||||
`libs/${myPkg}/src/{foo,bar}.ts`,
|
||||
];
|
||||
return config;
|
||||
});
|
||||
updateFile(
|
||||
`libs/${myPkg}/rollup.config.js`,
|
||||
`
|
||||
const { withNx } = require('@nx/rollup/with-nx');
|
||||
module.exports = withNx({
|
||||
outputPath: '../../dist/libs/${myPkg}',
|
||||
main: './src/index.ts',
|
||||
tsConfig: './tsconfig.lib.json',
|
||||
compiler: 'tsc',
|
||||
generateExportsField: true,
|
||||
additionalEntryPoints: ['./src/{foo,bar}.ts'],
|
||||
format: ['cjs', 'esm']
|
||||
});
|
||||
`
|
||||
);
|
||||
|
||||
updateFile(`libs/${myPkg}/src/foo.ts`, `export const foo = 'foo';`);
|
||||
updateFile(`libs/${myPkg}/src/bar.ts`, `export const bar = 'bar';`);
|
||||
|
||||
@ -121,49 +162,7 @@ describe('Rollup Plugin', () => {
|
||||
expect(() => runCLI(`build ${jsLib}`)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should be able to build libs generated with @nx/js:lib --bundler rollup with a custom rollup.config.{cjs|mjs}', () => {
|
||||
const jsLib = uniq('jslib');
|
||||
runCLI(`generate @nx/js:lib ${jsLib} --bundler rollup`);
|
||||
updateFile(
|
||||
`libs/${jsLib}/rollup.config.cjs`,
|
||||
`module.exports = {
|
||||
output: {
|
||||
format: "cjs",
|
||||
dir: "dist/test",
|
||||
name: "Mylib",
|
||||
entryFileNames: "[name].cjs.js",
|
||||
chunkFileNames: "[name].cjs.js"
|
||||
}
|
||||
}`
|
||||
);
|
||||
updateJson(join('libs', jsLib, 'project.json'), (config) => {
|
||||
config.targets.build.options.rollupConfig = `libs/${jsLib}/rollup.config.cjs`;
|
||||
return config;
|
||||
});
|
||||
expect(() => runCLI(`build ${jsLib}`)).not.toThrow();
|
||||
checkFilesExist(`dist/test/index.cjs.js`);
|
||||
|
||||
updateFile(
|
||||
`libs/${jsLib}/rollup.config.mjs`,
|
||||
`export default {
|
||||
output: {
|
||||
format: "es",
|
||||
dir: "dist/test",
|
||||
name: "Mylib",
|
||||
entryFileNames: "[name].mjs.js",
|
||||
chunkFileNames: "[name].mjs.js"
|
||||
}
|
||||
}`
|
||||
);
|
||||
updateJson(join('libs', jsLib, 'project.json'), (config) => {
|
||||
config.targets.build.options.rollupConfig = `libs/${jsLib}/rollup.config.mjs`;
|
||||
return config;
|
||||
});
|
||||
expect(() => runCLI(`build ${jsLib}`)).not.toThrow();
|
||||
checkFilesExist(`dist/test/index.mjs.js`);
|
||||
});
|
||||
|
||||
it('should build correctly with crystal', () => {
|
||||
it('should work correctly with custom, non-Nx rollup config', () => {
|
||||
// ARRANGE
|
||||
packageInstall('@rollup/plugin-babel', undefined, '5.3.0', 'prod');
|
||||
packageInstall('@rollup/plugin-commonjs', undefined, '25.0.7', 'prod');
|
||||
@ -216,30 +215,4 @@ export default config;
|
||||
checkFilesExist(`libs/test/dist/bundle.js`);
|
||||
checkFilesExist(`libs/test/dist/bundle.es.js`);
|
||||
});
|
||||
|
||||
it('should support array config from rollup.config.js', () => {
|
||||
const jsLib = uniq('jslib');
|
||||
runCLI(`generate @nx/js:lib ${jsLib} --bundler rollup --verbose`);
|
||||
updateFile(
|
||||
`libs/${jsLib}/rollup.config.js`,
|
||||
`module.exports = (config) => [{
|
||||
...config,
|
||||
output: {
|
||||
format: "esm",
|
||||
dir: "dist/test",
|
||||
name: "Mylib",
|
||||
entryFileNames: "[name].js",
|
||||
chunkFileNames: "[name].js"
|
||||
}
|
||||
}]`
|
||||
);
|
||||
updateJson(join('libs', jsLib, 'project.json'), (config) => {
|
||||
config.targets.build.options.rollupConfig = `libs/${jsLib}/rollup.config.js`;
|
||||
return config;
|
||||
});
|
||||
|
||||
expect(() => runCLI(`build ${jsLib} --format=esm`)).not.toThrow();
|
||||
|
||||
checkFilesExist(`dist/test/index.js`);
|
||||
});
|
||||
});
|
||||
|
||||
@ -58,6 +58,7 @@ interface LintProjectOptions {
|
||||
* @internal
|
||||
*/
|
||||
addExplicitTargets?: boolean;
|
||||
addPackageJsonDependencyChecks?: boolean;
|
||||
}
|
||||
|
||||
export function lintProjectGenerator(tree: Tree, options: LintProjectOptions) {
|
||||
@ -158,6 +159,7 @@ export async function lintProjectGeneratorInternal(
|
||||
if (!options.rootProject || projectConfig.root !== '.') {
|
||||
createEsLintConfiguration(
|
||||
tree,
|
||||
options,
|
||||
projectConfig,
|
||||
options.setParserOptionsProject,
|
||||
options.rootProject
|
||||
@ -188,6 +190,7 @@ export async function lintProjectGeneratorInternal(
|
||||
|
||||
function createEsLintConfiguration(
|
||||
tree: Tree,
|
||||
options: LintProjectOptions,
|
||||
projectConfig: ProjectConfiguration,
|
||||
setParserOptionsProject: boolean,
|
||||
rootProject: boolean
|
||||
@ -236,7 +239,10 @@ function createEsLintConfiguration(
|
||||
},
|
||||
];
|
||||
|
||||
if (isBuildableLibraryProject(projectConfig)) {
|
||||
if (
|
||||
options.addPackageJsonDependencyChecks ||
|
||||
isBuildableLibraryProject(projectConfig)
|
||||
) {
|
||||
overrides.push({
|
||||
files: ['*.json'],
|
||||
parser: 'jsonc-eslint-parser',
|
||||
|
||||
@ -974,11 +974,6 @@ describe('lib', () => {
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
const config = readProjectConfiguration(tree, 'my-lib');
|
||||
expect(config.targets.build.options.project).toEqual(
|
||||
`my-lib/package.json`
|
||||
);
|
||||
|
||||
const pkgJson = readJson(tree, 'my-lib/package.json');
|
||||
expect(pkgJson.type).not.toBeDefined();
|
||||
});
|
||||
@ -990,9 +985,6 @@ describe('lib', () => {
|
||||
bundler: 'rollup',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
const config = readProjectConfiguration(tree, 'my-lib');
|
||||
expect(config.targets.build.options.compiler).toEqual('swc');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1509,10 +1501,6 @@ describe('lib', () => {
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'my-lib');
|
||||
expect(project.targets.build).toMatchObject({
|
||||
executor: '@nx/rollup:rollup',
|
||||
});
|
||||
expect(readJson(tree, 'my-lib/.eslintrc.json').overrides).toContainEqual({
|
||||
files: ['*.json'],
|
||||
parser: 'jsonc-eslint-parser',
|
||||
|
||||
@ -89,6 +89,15 @@ export async function libraryGeneratorInternal(
|
||||
tasks.push(await setupVerdaccio(tree, { ...options, skipFormat: true }));
|
||||
}
|
||||
|
||||
if (options.bundler === 'rollup') {
|
||||
const { configurationGenerator } = ensurePackage('@nx/rollup', nxVersion);
|
||||
await configurationGenerator(tree, {
|
||||
project: options.name,
|
||||
compiler: 'swc',
|
||||
format: ['cjs', 'esm'],
|
||||
});
|
||||
}
|
||||
|
||||
if (options.bundler === 'vite') {
|
||||
const { viteConfigurationGenerator, createOrEditViteConfig } =
|
||||
ensurePackage('@nx/vite', nxVersion);
|
||||
@ -207,47 +216,38 @@ async function addProject(tree: Tree, options: NormalizedSchema) {
|
||||
options.bundler !== 'none' &&
|
||||
options.config !== 'npm-scripts'
|
||||
) {
|
||||
const outputPath = getOutputPath(options);
|
||||
if (options.bundler !== 'rollup') {
|
||||
const outputPath = getOutputPath(options);
|
||||
const executor = getBuildExecutor(options.bundler);
|
||||
addBuildTargetDefaults(tree, executor);
|
||||
|
||||
const executor = getBuildExecutor(options.bundler);
|
||||
projectConfiguration.targets.build = {
|
||||
executor,
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
outputPath,
|
||||
main:
|
||||
`${options.projectRoot}/src/index` + (options.js ? '.js' : '.ts'),
|
||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||
assets: [],
|
||||
},
|
||||
};
|
||||
|
||||
addBuildTargetDefaults(tree, executor);
|
||||
if (options.bundler === 'esbuild') {
|
||||
projectConfiguration.targets.build.options.generatePackageJson = true;
|
||||
projectConfiguration.targets.build.options.format = ['cjs'];
|
||||
}
|
||||
|
||||
projectConfiguration.targets.build = {
|
||||
executor,
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
outputPath,
|
||||
main: `${options.projectRoot}/src/index` + (options.js ? '.js' : '.ts'),
|
||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||
assets: [],
|
||||
},
|
||||
};
|
||||
if (options.bundler === 'swc' && options.skipTypeCheck) {
|
||||
projectConfiguration.targets.build.options.skipTypeCheck = true;
|
||||
}
|
||||
|
||||
if (options.bundler === 'esbuild') {
|
||||
projectConfiguration.targets.build.options.generatePackageJson = true;
|
||||
projectConfiguration.targets.build.options.format = ['cjs'];
|
||||
}
|
||||
|
||||
if (options.bundler === 'rollup') {
|
||||
projectConfiguration.targets.build.options.project = `${options.projectRoot}/package.json`;
|
||||
projectConfiguration.targets.build.options.compiler = 'swc';
|
||||
projectConfiguration.targets.build.options.format = ['cjs', 'esm'];
|
||||
}
|
||||
|
||||
if (options.bundler === 'swc' && options.skipTypeCheck) {
|
||||
projectConfiguration.targets.build.options.skipTypeCheck = true;
|
||||
}
|
||||
|
||||
if (
|
||||
!options.minimal &&
|
||||
// TODO(jack): assets for rollup have validation that we need to fix (assets must be under <project-root>/src)
|
||||
options.bundler !== 'rollup'
|
||||
) {
|
||||
projectConfiguration.targets.build.options.assets ??= [];
|
||||
projectConfiguration.targets.build.options.assets.push(
|
||||
joinPathFragments(options.projectRoot, '*.md')
|
||||
);
|
||||
if (!options.minimal) {
|
||||
projectConfiguration.targets.build.options.assets ??= [];
|
||||
projectConfiguration.targets.build.options.assets.push(
|
||||
joinPathFragments(options.projectRoot, '*.md')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.publishable) {
|
||||
@ -321,6 +321,8 @@ export async function addLint(
|
||||
setParserOptionsProject: options.setParserOptionsProject,
|
||||
rootProject: options.rootProject,
|
||||
addPlugin: options.addPlugin,
|
||||
// Since the build target is inferred now, we need to let the generator know to add @nx/dependency-checks regardless.
|
||||
addPackageJsonDependencyChecks: options.bundler !== 'none',
|
||||
});
|
||||
const {
|
||||
addOverrideToLintConfig,
|
||||
|
||||
@ -138,19 +138,7 @@ describe('setup-build generator', () => {
|
||||
bundler: 'rollup',
|
||||
});
|
||||
|
||||
const config = readProjectConfiguration(tree, 'mypkg');
|
||||
expect(config).toMatchObject({
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
options: {
|
||||
outputPath: 'dist/packages/mypkg',
|
||||
main: 'packages/mypkg/src/main.ts',
|
||||
tsConfig: 'packages/mypkg/tsconfig.lib.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree.exists('packages/mypkg/rollup.config.js')).toBe(true);
|
||||
});
|
||||
|
||||
it('should support --bundler=esbuild', async () => {
|
||||
|
||||
@ -16,10 +16,7 @@ import { stripIndents } from '@nx/devkit';
|
||||
* We want a third file: `dist/index.d.ts` that re-exports from `src/index.d.ts`.
|
||||
* That way, when TSC or IDEs look for types, it will find them in the right place.
|
||||
*/
|
||||
export function typeDefinitions(options: {
|
||||
projectRoot: string;
|
||||
main: string;
|
||||
}) {
|
||||
export function typeDefinitions(options: { projectRoot: string }) {
|
||||
return {
|
||||
name: 'dts-bundle',
|
||||
async generateBundle(_opts: unknown, bundle: OutputBundle): Promise<void> {
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
import { Tree } from 'nx/src/generators/tree';
|
||||
import {
|
||||
GeneratorCallback,
|
||||
addDependenciesToPackageJson,
|
||||
ensurePackage,
|
||||
GeneratorCallback,
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
runTasksInSerial,
|
||||
stripIndents,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
|
||||
@ -49,8 +52,6 @@ export async function addRollupBuildTarget(
|
||||
);
|
||||
}
|
||||
|
||||
const { targets } = readProjectConfiguration(host, options.name);
|
||||
|
||||
const external: string[] = ['react', 'react-dom'];
|
||||
|
||||
if (options.style === '@emotion/styled') {
|
||||
@ -59,34 +60,80 @@ export async function addRollupBuildTarget(
|
||||
external.push('react/jsx-runtime');
|
||||
}
|
||||
|
||||
targets.build = {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
outputPath: joinPathFragments('dist', options.projectRoot),
|
||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||
project: `${options.projectRoot}/package.json`,
|
||||
entryFile: maybeJs(options, `${options.projectRoot}/src/index.ts`),
|
||||
external,
|
||||
rollupConfig: `@nx/react/plugins/bundle-rollup`,
|
||||
compiler: options.compiler ?? 'babel',
|
||||
assets: [
|
||||
{
|
||||
glob: `${options.projectRoot}/README.md`,
|
||||
input: '.',
|
||||
output: '.',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const nxJson = readNxJson(host);
|
||||
const hasRollupPlugin = !!nxJson.plugins?.some((p) =>
|
||||
typeof p === 'string'
|
||||
? p === '@nx/rollup/plugin'
|
||||
: p.plugin === '@nx/rollup/plugin'
|
||||
);
|
||||
if (hasRollupPlugin) {
|
||||
// New behavior, using rollup config file and inferred target.
|
||||
host.write(
|
||||
joinPathFragments(options.projectRoot, 'rollup.config.js'),
|
||||
stripIndents`
|
||||
const { withNx } = require('@nx/rollup/with-nx');
|
||||
const url = require('@rollup/plugin-url');
|
||||
const svg = require('@svgr/rollup');
|
||||
|
||||
module.exports = withNx({
|
||||
main: '${maybeJs(options, './src/index.ts')}',
|
||||
outputPath: '${joinPathFragments(
|
||||
offsetFromRoot(options.projectRoot),
|
||||
'dist',
|
||||
options.projectRoot
|
||||
)}',
|
||||
tsConfig: './tsconfig.lib.json',
|
||||
compiler: '${options.compiler ?? 'babel'}',
|
||||
external: ${JSON.stringify(external)},
|
||||
format: ['esm'],
|
||||
assets:[{ input: '.', output: '.', glob: 'README.md'}],
|
||||
}, {
|
||||
// Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
|
||||
plugins: [
|
||||
svg({
|
||||
svgo: false,
|
||||
titleProp: true,
|
||||
ref: true,
|
||||
}),
|
||||
url({
|
||||
limit: 10000, // 10kB
|
||||
}),
|
||||
],
|
||||
});
|
||||
`
|
||||
);
|
||||
} else {
|
||||
// Legacy behavior, there is a target in project.json using rollup executor.
|
||||
const { targets } = readProjectConfiguration(host, options.name);
|
||||
targets.build = {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
outputPath: joinPathFragments('dist', options.projectRoot),
|
||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||
project: `${options.projectRoot}/package.json`,
|
||||
entryFile: maybeJs(options, `${options.projectRoot}/src/index.ts`),
|
||||
external,
|
||||
rollupConfig: `@nx/react/plugins/bundle-rollup`,
|
||||
compiler: options.compiler ?? 'babel',
|
||||
assets: [
|
||||
{
|
||||
glob: `${options.projectRoot}/README.md`,
|
||||
input: '.',
|
||||
output: '.',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
updateProjectConfiguration(host, options.name, {
|
||||
root: options.projectRoot,
|
||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||
projectType: 'library',
|
||||
tags: options.parsedTags,
|
||||
targets,
|
||||
});
|
||||
updateProjectConfiguration(host, options.name, {
|
||||
root: options.projectRoot,
|
||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||
projectType: 'library',
|
||||
tags: options.parsedTags,
|
||||
targets,
|
||||
});
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
@ -496,25 +496,93 @@ describe('lib', () => {
|
||||
});
|
||||
|
||||
describe('--buildable', () => {
|
||||
it('should have a builder defined', async () => {
|
||||
it('should default to rollup bundler', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
buildable: true,
|
||||
});
|
||||
|
||||
const projectsConfigurations = getProjects(tree);
|
||||
expect(projectsConfigurations.get('my-lib').targets.build).toBeDefined();
|
||||
expect(tree.exists('my-lib/rollup.config.js')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('--publishable', () => {
|
||||
it('should add build targets', async () => {
|
||||
it('should fail if no importPath is provided with publishable', async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
try {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
directory: 'myDir',
|
||||
publishable: true,
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.message).toContain(
|
||||
'For publishable libs you have to provide a proper "--importPath" which needs to be a valid npm package name (e.g. my-awesome-lib or @myorg/my-lib)'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should add package.json and .babelrc', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
publishable: true,
|
||||
importPath: '@proj/my-lib',
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, '/my-lib/package.json');
|
||||
expect(packageJson.name).toEqual('@proj/my-lib');
|
||||
expect(tree.exists('/my-lib/.babelrc'));
|
||||
});
|
||||
|
||||
it('should add rollup config file', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
skipFormat: false,
|
||||
publishable: true,
|
||||
importPath: '@proj/my-lib',
|
||||
});
|
||||
|
||||
expect(tree.read('my-lib/rollup.config.js', 'utf-8'))
|
||||
.toEqual(`const { withNx } = require('@nx/rollup/with-nx');
|
||||
const url = require('@rollup/plugin-url');
|
||||
const svg = require('@svgr/rollup');
|
||||
|
||||
module.exports = withNx(
|
||||
{
|
||||
main: './src/index.ts',
|
||||
outputPath: '../dist/my-lib',
|
||||
tsConfig: './tsconfig.lib.json',
|
||||
compiler: 'babel',
|
||||
external: ['react', 'react-dom', 'react/jsx-runtime'],
|
||||
format: ['esm'],
|
||||
assets: [{ input: '.', output: '.', glob: 'README.md' }],
|
||||
},
|
||||
{
|
||||
// Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
|
||||
plugins: [
|
||||
svg({
|
||||
svgo: false,
|
||||
titleProp: true,
|
||||
ref: true,
|
||||
}),
|
||||
url({
|
||||
limit: 10000, // 10kB
|
||||
}),
|
||||
],
|
||||
}
|
||||
);
|
||||
`);
|
||||
});
|
||||
|
||||
it('should add build targets (legacy)', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
addPlugin: false,
|
||||
publishable: true,
|
||||
importPath: '@proj/my-lib',
|
||||
});
|
||||
|
||||
const projectsConfigurations = getProjects(tree);
|
||||
|
||||
expect(projectsConfigurations.get('my-lib').targets.build).toMatchObject({
|
||||
@ -531,25 +599,10 @@ describe('lib', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail if no importPath is provided with publishable', async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
try {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
directory: 'myDir',
|
||||
publishable: true,
|
||||
});
|
||||
} catch (e) {
|
||||
expect(e.message).toContain(
|
||||
'For publishable libs you have to provide a proper "--importPath" which needs to be a valid npm package name (e.g. my-awesome-lib or @myorg/my-lib)'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should support styled-components', async () => {
|
||||
it('should support styled-components (legacy)', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
addPlugin: false,
|
||||
publishable: true,
|
||||
importPath: '@proj/my-lib',
|
||||
style: 'styled-components',
|
||||
@ -568,9 +621,10 @@ describe('lib', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('should support @emotion/styled', async () => {
|
||||
it('should support @emotion/styled (legacy)', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
addPlugin: false,
|
||||
publishable: true,
|
||||
importPath: '@proj/my-lib',
|
||||
style: '@emotion/styled',
|
||||
@ -591,9 +645,10 @@ describe('lib', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should support styled-jsx', async () => {
|
||||
it('should support styled-jsx (legacy)', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
addPlugin: false,
|
||||
publishable: true,
|
||||
importPath: '@proj/my-lib',
|
||||
style: 'styled-jsx',
|
||||
@ -610,9 +665,10 @@ describe('lib', () => {
|
||||
expect(babelrc.plugins).toEqual(['styled-jsx/babel']);
|
||||
});
|
||||
|
||||
it('should support style none', async () => {
|
||||
it('should support style none (legacy)', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
addPlugin: false,
|
||||
publishable: true,
|
||||
importPath: '@proj/my-lib',
|
||||
style: 'none',
|
||||
@ -626,18 +682,6 @@ describe('lib', () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should add package.json and .babelrc', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
publishable: true,
|
||||
importPath: '@proj/my-lib',
|
||||
});
|
||||
|
||||
const packageJson = readJson(tree, '/my-lib/package.json');
|
||||
expect(packageJson.name).toEqual('@proj/my-lib');
|
||||
expect(tree.exists('/my-lib/.babelrc'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('--js', () => {
|
||||
|
||||
@ -4,7 +4,6 @@ import { RollupExecutorOptions } from '../schema';
|
||||
describe('normalizeRollupExecutorOptions', () => {
|
||||
let testOptions: RollupExecutorOptions;
|
||||
let root: string;
|
||||
let sourceRoot: string;
|
||||
|
||||
beforeEach(() => {
|
||||
testOptions = {
|
||||
@ -16,15 +15,16 @@ describe('normalizeRollupExecutorOptions', () => {
|
||||
format: ['esm'],
|
||||
};
|
||||
root = '/root';
|
||||
sourceRoot = 'apps/nodeapp/src';
|
||||
});
|
||||
|
||||
it('should resolve both node modules and relative path for rollupConfig', () => {
|
||||
let result = normalizeRollupExecutorOptions(
|
||||
testOptions,
|
||||
{ root } as any,
|
||||
sourceRoot
|
||||
);
|
||||
let result = normalizeRollupExecutorOptions(testOptions, {
|
||||
root,
|
||||
projectGraph: {
|
||||
nodes: { nodeapp: { data: { root: 'apps/nodeapp' } } },
|
||||
},
|
||||
projectName: 'nodeapp',
|
||||
} as any);
|
||||
expect(result.rollupConfig).toEqual(['/root/apps/nodeapp/rollup.config']);
|
||||
|
||||
result = normalizeRollupExecutorOptions(
|
||||
@ -33,8 +33,13 @@ describe('normalizeRollupExecutorOptions', () => {
|
||||
// something that exists in node_modules
|
||||
rollupConfig: 'react',
|
||||
},
|
||||
{ root } as any,
|
||||
sourceRoot
|
||||
{
|
||||
root,
|
||||
projectGraph: {
|
||||
nodes: { nodeapp: { data: { root: 'apps/nodeapp' } } },
|
||||
},
|
||||
projectName: 'nodeapp',
|
||||
} as any
|
||||
);
|
||||
expect(result.rollupConfig).toHaveLength(1);
|
||||
expect(result.rollupConfig[0]).toMatch('react');
|
||||
@ -45,11 +50,13 @@ describe('normalizeRollupExecutorOptions', () => {
|
||||
it('should handle rollupConfig being undefined', () => {
|
||||
delete testOptions.rollupConfig;
|
||||
|
||||
const result = normalizeRollupExecutorOptions(
|
||||
testOptions,
|
||||
{ root } as any,
|
||||
sourceRoot
|
||||
);
|
||||
const result = normalizeRollupExecutorOptions(testOptions, {
|
||||
root,
|
||||
projectGraph: {
|
||||
nodes: { nodeapp: { data: { root: 'apps/nodeapp' } } },
|
||||
},
|
||||
projectName: 'nodeapp',
|
||||
} as any);
|
||||
expect(result.rollupConfig).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,52 +1,26 @@
|
||||
import { basename, dirname, join, relative, resolve } from 'path';
|
||||
import { statSync } from 'fs';
|
||||
import { ExecutorContext, normalizePath } from '@nx/devkit';
|
||||
import { resolve } from 'path';
|
||||
import { ExecutorContext } from '@nx/devkit';
|
||||
|
||||
import type { AssetGlobPattern, RollupExecutorOptions } from '../schema';
|
||||
import { createEntryPoints } from '@nx/js';
|
||||
import type { RollupExecutorOptions } from '../schema';
|
||||
|
||||
export interface NormalizedRollupExecutorOptions extends RollupExecutorOptions {
|
||||
entryRoot: string;
|
||||
projectRoot: string;
|
||||
assets: AssetGlobPattern[];
|
||||
rollupConfig: string[];
|
||||
}
|
||||
|
||||
export function normalizeRollupExecutorOptions(
|
||||
options: RollupExecutorOptions,
|
||||
context: ExecutorContext,
|
||||
sourceRoot: string
|
||||
context: ExecutorContext
|
||||
): NormalizedRollupExecutorOptions {
|
||||
const { root } = context;
|
||||
const main = `${root}/${options.main}`;
|
||||
const entryRoot = dirname(main);
|
||||
const project = options.project
|
||||
? `${root}/${options.project}`
|
||||
: join(root, 'package.json');
|
||||
const projectRoot = dirname(project);
|
||||
const outputPath = `${root}/${options.outputPath}`;
|
||||
|
||||
return {
|
||||
...options,
|
||||
// de-dupe formats
|
||||
format: Array.from(new Set(options.format)),
|
||||
rollupConfig: []
|
||||
.concat(options.rollupConfig)
|
||||
.filter(Boolean)
|
||||
.map((p) => normalizePluginPath(p, root)),
|
||||
assets: options.assets
|
||||
? normalizeAssets(options.assets, root, sourceRoot)
|
||||
: undefined,
|
||||
main,
|
||||
entryRoot,
|
||||
project,
|
||||
projectRoot,
|
||||
outputPath,
|
||||
projectRoot: context.projectGraph.nodes[context.projectName].data.root,
|
||||
skipTypeCheck: options.skipTypeCheck || false,
|
||||
additionalEntryPoints: createEntryPoints(
|
||||
options.additionalEntryPoints,
|
||||
context.root
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@ -60,50 +34,3 @@ export function normalizePluginPath(pluginPath: void | string, root: string) {
|
||||
return resolve(root, pluginPath);
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeAssets(
|
||||
assets: any[],
|
||||
root: string,
|
||||
sourceRoot: string
|
||||
): AssetGlobPattern[] {
|
||||
return assets.map((asset) => {
|
||||
if (typeof asset === 'string') {
|
||||
const assetPath = normalizePath(asset);
|
||||
const resolvedAssetPath = resolve(root, assetPath);
|
||||
const resolvedSourceRoot = resolve(root, sourceRoot);
|
||||
|
||||
if (!resolvedAssetPath.startsWith(resolvedSourceRoot)) {
|
||||
throw new Error(
|
||||
`The ${resolvedAssetPath} asset path must start with the project source root: ${sourceRoot}`
|
||||
);
|
||||
}
|
||||
|
||||
const isDirectory = statSync(resolvedAssetPath).isDirectory();
|
||||
const input = isDirectory
|
||||
? resolvedAssetPath
|
||||
: dirname(resolvedAssetPath);
|
||||
const output = relative(resolvedSourceRoot, resolve(root, input));
|
||||
const glob = isDirectory ? '**/*' : basename(resolvedAssetPath);
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
glob,
|
||||
};
|
||||
} else {
|
||||
if (asset.output.startsWith('..')) {
|
||||
throw new Error(
|
||||
'An asset cannot be written to a location outside of the output path.'
|
||||
);
|
||||
}
|
||||
|
||||
const assetPath = normalizePath(asset.input);
|
||||
const resolvedAssetPath = resolve(root, assetPath);
|
||||
return {
|
||||
...asset,
|
||||
input: resolvedAssetPath,
|
||||
// Now we remove starting slash to make Webpack place it from the output root.
|
||||
output: asset.output.replace(/^\//, ''),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,85 +1,24 @@
|
||||
import * as ts from 'typescript';
|
||||
import * as rollup from 'rollup';
|
||||
import { getBabelInputPlugin } from '@rollup/plugin-babel';
|
||||
import { dirname, join, parse, resolve } from 'path';
|
||||
import * as autoprefixer from 'autoprefixer';
|
||||
import {
|
||||
type ExecutorContext,
|
||||
joinPathFragments,
|
||||
logger,
|
||||
names,
|
||||
readJsonFile,
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
calculateProjectBuildableDependencies,
|
||||
computeCompilerOptionsPaths,
|
||||
DependentBuildableProjectNode,
|
||||
} from '@nx/js/src/utils/buildable-libs-utils';
|
||||
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { typeDefinitions } from '@nx/js/src/plugins/rollup/type-definitions';
|
||||
import { parse, resolve } from 'path';
|
||||
import { type ExecutorContext, logger } from '@nx/devkit';
|
||||
|
||||
import { AssetGlobPattern, RollupExecutorOptions } from './schema';
|
||||
import { RollupExecutorOptions } from './schema';
|
||||
import {
|
||||
NormalizedRollupExecutorOptions,
|
||||
normalizeRollupExecutorOptions,
|
||||
} from './lib/normalize';
|
||||
import { analyze } from './lib/analyze-plugin';
|
||||
import { deleteOutputDir } from '../../utils/fs';
|
||||
import { swc } from './lib/swc-plugin';
|
||||
import { updatePackageJson } from './lib/update-package-json';
|
||||
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
|
||||
import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable';
|
||||
|
||||
// These use require because the ES import isn't correct.
|
||||
const commonjs = require('@rollup/plugin-commonjs');
|
||||
const image = require('@rollup/plugin-image');
|
||||
|
||||
const json = require('@rollup/plugin-json');
|
||||
const copy = require('rollup-plugin-copy');
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
|
||||
const fileExtensions = ['.js', '.jsx', '.ts', '.tsx'];
|
||||
import { withNx } from '../../plugins/with-nx/with-nx';
|
||||
import { calculateProjectBuildableDependencies } from '@nx/js/src/utils/buildable-libs-utils';
|
||||
|
||||
export async function* rollupExecutor(
|
||||
rawOptions: RollupExecutorOptions,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
process.env.NODE_ENV ??= 'production';
|
||||
|
||||
const project = context.projectsConfigurations.projects[context.projectName];
|
||||
const sourceRoot = project.sourceRoot;
|
||||
const { dependencies } = calculateProjectBuildableDependencies(
|
||||
context.taskGraph,
|
||||
context.projectGraph,
|
||||
context.root,
|
||||
context.projectName,
|
||||
context.targetName,
|
||||
context.configurationName,
|
||||
true
|
||||
);
|
||||
|
||||
const options = normalizeRollupExecutorOptions(
|
||||
rawOptions,
|
||||
context,
|
||||
sourceRoot
|
||||
);
|
||||
|
||||
const packageJson = readJsonFile(options.project);
|
||||
|
||||
const npmDeps = (context.projectGraph.dependencies[context.projectName] ?? [])
|
||||
.filter((d) => d.target.startsWith('npm:'))
|
||||
.map((d) => d.target.slice(4));
|
||||
|
||||
const rollupOptions = await createRollupOptions(
|
||||
options,
|
||||
dependencies,
|
||||
context,
|
||||
packageJson,
|
||||
sourceRoot,
|
||||
npmDeps
|
||||
);
|
||||
|
||||
const options = normalizeRollupExecutorOptions(rawOptions, context);
|
||||
const rollupOptions = await createRollupOptions(options, context);
|
||||
const outfile = resolveOutfile(context, options);
|
||||
|
||||
if (options.watch) {
|
||||
@ -90,7 +29,6 @@ export async function* rollupExecutor(
|
||||
if (data.code === 'START') {
|
||||
logger.info(`Bundling ${context.projectName}...`);
|
||||
} else if (data.code === 'END') {
|
||||
updatePackageJson(options, packageJson);
|
||||
logger.info('Bundle complete. Watching for file changes...');
|
||||
next({ success: true, outfile });
|
||||
} else if (data.code === 'ERROR') {
|
||||
@ -111,11 +49,6 @@ export async function* rollupExecutor(
|
||||
try {
|
||||
logger.info(`Bundling ${context.projectName}...`);
|
||||
|
||||
// Delete output path before bundling
|
||||
if (options.deleteOutputPath) {
|
||||
deleteOutputDir(context.root, options.outputPath);
|
||||
}
|
||||
|
||||
const start = process.hrtime.bigint();
|
||||
const allRollupOptions = Array.isArray(rollupOptions)
|
||||
? rollupOptions
|
||||
@ -133,7 +66,6 @@ export async function* rollupExecutor(
|
||||
const end = process.hrtime.bigint();
|
||||
const duration = `${(Number(end - start) / 1_000_000_000).toFixed(2)}s`;
|
||||
|
||||
updatePackageJson(options, packageJson);
|
||||
logger.info(`⚡ Done in ${duration}`);
|
||||
return { success: true, outfile };
|
||||
} catch (e) {
|
||||
@ -154,140 +86,19 @@ export async function* rollupExecutor(
|
||||
|
||||
export async function createRollupOptions(
|
||||
options: NormalizedRollupExecutorOptions,
|
||||
dependencies: DependentBuildableProjectNode[],
|
||||
context: ExecutorContext,
|
||||
packageJson: PackageJson,
|
||||
sourceRoot: string,
|
||||
npmDeps: string[]
|
||||
context: ExecutorContext
|
||||
): Promise<rollup.RollupOptions | rollup.RollupOptions[]> {
|
||||
const useBabel = options.compiler === 'babel';
|
||||
const useSwc = options.compiler === 'swc';
|
||||
|
||||
const tsConfigPath = joinPathFragments(context.root, options.tsConfig);
|
||||
const configFile = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
|
||||
const config = ts.parseJsonConfigFileContent(
|
||||
configFile.config,
|
||||
ts.sys,
|
||||
dirname(tsConfigPath)
|
||||
const { dependencies } = calculateProjectBuildableDependencies(
|
||||
context.taskGraph,
|
||||
context.projectGraph,
|
||||
context.root,
|
||||
context.projectName,
|
||||
context.targetName,
|
||||
context.configurationName,
|
||||
true
|
||||
);
|
||||
|
||||
if (!options.format || !options.format.length) {
|
||||
options.format = readCompatibleFormats(config);
|
||||
}
|
||||
|
||||
if (packageJson.type === 'module') {
|
||||
if (options.format.includes('cjs')) {
|
||||
logger.warn(
|
||||
`Package type is set to "module" but "cjs" format is included. Going to use "esm" format instead. You can change the package type to "commonjs" or remove type in the package.json file.`
|
||||
);
|
||||
}
|
||||
options.format = ['esm'];
|
||||
} else if (packageJson.type === 'commonjs') {
|
||||
if (options.format.includes('esm')) {
|
||||
logger.warn(
|
||||
`Package type is set to "commonjs" but "esm" format is included. Going to use "cjs" format instead. You can change the package type to "module" or remove type in the package.json file.`
|
||||
);
|
||||
}
|
||||
options.format = ['cjs'];
|
||||
}
|
||||
|
||||
const plugins = [
|
||||
copy({
|
||||
targets: convertCopyAssetsToRollupOptions(
|
||||
options.outputPath,
|
||||
options.assets
|
||||
),
|
||||
}),
|
||||
image(),
|
||||
json(),
|
||||
// Needed to generate type definitions, even if we're using babel or swc.
|
||||
require('rollup-plugin-typescript2')({
|
||||
check: !options.skipTypeCheck,
|
||||
tsconfig: options.tsConfig,
|
||||
tsconfigOverride: {
|
||||
compilerOptions: createTsCompilerOptions(config, dependencies, options),
|
||||
},
|
||||
}),
|
||||
|
||||
typeDefinitions({
|
||||
main: options.main,
|
||||
projectRoot: options.projectRoot,
|
||||
}),
|
||||
postcss({
|
||||
inject: true,
|
||||
extract: options.extractCss,
|
||||
autoModules: true,
|
||||
plugins: [autoprefixer],
|
||||
use: {
|
||||
less: {
|
||||
javascriptEnabled: options.javascriptEnabled,
|
||||
},
|
||||
},
|
||||
}),
|
||||
nodeResolve({
|
||||
preferBuiltins: true,
|
||||
extensions: fileExtensions,
|
||||
}),
|
||||
useSwc && swc(),
|
||||
useBabel &&
|
||||
getBabelInputPlugin({
|
||||
// Lets `@nx/js/babel` preset know that we are packaging.
|
||||
caller: {
|
||||
// @ts-ignore
|
||||
// Ignoring type checks for caller since we have custom attributes
|
||||
isNxPackage: true,
|
||||
// Always target esnext and let rollup handle cjs
|
||||
supportsStaticESM: true,
|
||||
isModern: true,
|
||||
},
|
||||
cwd: join(context.root, sourceRoot),
|
||||
rootMode: options.babelUpwardRootMode ? 'upward' : undefined,
|
||||
babelrc: true,
|
||||
extensions: fileExtensions,
|
||||
babelHelpers: 'bundled',
|
||||
skipPreflightCheck: true, // pre-flight check may yield false positives and also slows down the build
|
||||
exclude: /node_modules/,
|
||||
}),
|
||||
commonjs(),
|
||||
analyze(),
|
||||
];
|
||||
|
||||
let externalPackages = [
|
||||
...Object.keys(packageJson.dependencies || {}),
|
||||
...Object.keys(packageJson.peerDependencies || {}),
|
||||
]; // If external is set to none, include all dependencies and peerDependencies in externalPackages
|
||||
if (options.external === 'all') {
|
||||
externalPackages = externalPackages
|
||||
.concat(dependencies.map((d) => d.name))
|
||||
.concat(npmDeps);
|
||||
} else if (Array.isArray(options.external) && options.external.length > 0) {
|
||||
externalPackages = externalPackages.concat(options.external);
|
||||
}
|
||||
externalPackages = [...new Set(externalPackages)];
|
||||
|
||||
const mainEntryFileName = options.outputFileName || options.main;
|
||||
const input: Record<string, string> = {};
|
||||
input[parse(mainEntryFileName).name] = options.main;
|
||||
options.additionalEntryPoints.forEach((entry) => {
|
||||
input[parse(entry).name] = entry;
|
||||
});
|
||||
|
||||
const rollupConfig = {
|
||||
input,
|
||||
output: options.format.map((format) => ({
|
||||
format,
|
||||
dir: `${options.outputPath}`,
|
||||
name: names(context.projectName).className,
|
||||
entryFileNames: `[name].${format}.js`,
|
||||
chunkFileNames: `[name].${format}.js`,
|
||||
})),
|
||||
external: (id: string) => {
|
||||
return externalPackages.some(
|
||||
(name) => id === name || id.startsWith(`${name}/`)
|
||||
); // Could be a deep import
|
||||
},
|
||||
plugins,
|
||||
};
|
||||
const rollupConfig = withNx(options, {}, dependencies);
|
||||
|
||||
const userDefinedRollupConfigs = options.rollupConfig.map((plugin) =>
|
||||
loadConfigFile(plugin)
|
||||
@ -314,57 +125,6 @@ export async function createRollupOptions(
|
||||
return finalConfig;
|
||||
}
|
||||
|
||||
function createTsCompilerOptions(
|
||||
config: ts.ParsedCommandLine,
|
||||
dependencies: DependentBuildableProjectNode[],
|
||||
options: NormalizedRollupExecutorOptions
|
||||
) {
|
||||
const compilerOptionPaths = computeCompilerOptionsPaths(config, dependencies);
|
||||
const compilerOptions = {
|
||||
rootDir: options.projectRoot,
|
||||
allowJs: options.allowJs,
|
||||
declaration: true,
|
||||
paths: compilerOptionPaths,
|
||||
};
|
||||
if (config.options.module === ts.ModuleKind.CommonJS) {
|
||||
compilerOptions['module'] = 'ESNext';
|
||||
}
|
||||
if (options.compiler === 'swc') {
|
||||
compilerOptions['emitDeclarationOnly'] = true;
|
||||
}
|
||||
return compilerOptions;
|
||||
}
|
||||
|
||||
interface RollupCopyAssetOption {
|
||||
src: string;
|
||||
dest: string;
|
||||
}
|
||||
|
||||
function convertCopyAssetsToRollupOptions(
|
||||
outputPath: string,
|
||||
assets: AssetGlobPattern[]
|
||||
): RollupCopyAssetOption[] {
|
||||
return assets
|
||||
? assets.map((a) => ({
|
||||
src: join(a.input, a.glob).replace(/\\/g, '/'),
|
||||
dest: join(outputPath, a.output).replace(/\\/g, '/'),
|
||||
}))
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function readCompatibleFormats(
|
||||
config: ts.ParsedCommandLine
|
||||
): ('cjs' | 'esm')[] {
|
||||
switch (config.options.module) {
|
||||
case ts.ModuleKind.CommonJS:
|
||||
case ts.ModuleKind.UMD:
|
||||
case ts.ModuleKind.AMD:
|
||||
return ['cjs'];
|
||||
default:
|
||||
return ['esm'];
|
||||
}
|
||||
}
|
||||
|
||||
function resolveOutfile(
|
||||
context: ExecutorContext,
|
||||
options: NormalizedRollupExecutorOptions
|
||||
|
||||
@ -0,0 +1,148 @@
|
||||
import 'nx/src/internal-testing-utils/mock-project-graph';
|
||||
|
||||
import {
|
||||
addProjectConfiguration,
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
|
||||
import configurationGenerator from './configuration';
|
||||
|
||||
describe('configurationGenerator', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(async () => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
addProjectConfiguration(tree, 'mypkg', {
|
||||
root: 'libs/mypkg',
|
||||
sourceRoot: 'libs/mypkg/src',
|
||||
targets: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate files', async () => {
|
||||
await configurationGenerator(tree, {
|
||||
addPlugin: false,
|
||||
project: 'mypkg',
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'mypkg');
|
||||
|
||||
expect(project.targets).toMatchObject({
|
||||
build: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
main: 'libs/mypkg/src/index.ts',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'libs/mypkg/package.json')).toEqual({
|
||||
name: '@proj/mypkg',
|
||||
version: '0.0.1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should respect existing package.json file', async () => {
|
||||
writeJson(tree, 'libs/mypkg/package.json', {
|
||||
name: '@acme/mypkg',
|
||||
version: '1.0.0',
|
||||
});
|
||||
await configurationGenerator(tree, {
|
||||
addPlugin: false,
|
||||
project: 'mypkg',
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'libs/mypkg/package.json')).toEqual({
|
||||
name: '@acme/mypkg',
|
||||
version: '1.0.0',
|
||||
});
|
||||
});
|
||||
|
||||
it('should support --main option', async () => {
|
||||
await configurationGenerator(tree, {
|
||||
addPlugin: false,
|
||||
project: 'mypkg',
|
||||
main: 'libs/mypkg/index.ts',
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'mypkg');
|
||||
|
||||
expect(project.targets).toMatchObject({
|
||||
build: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
main: 'libs/mypkg/index.ts',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should support --tsConfig option', async () => {
|
||||
await configurationGenerator(tree, {
|
||||
addPlugin: false,
|
||||
project: 'mypkg',
|
||||
tsConfig: 'libs/mypkg/tsconfig.custom.json',
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'mypkg');
|
||||
|
||||
expect(project.targets).toMatchObject({
|
||||
build: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
tsConfig: 'libs/mypkg/tsconfig.custom.json',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should carry over known executor options from existing build target', async () => {
|
||||
updateProjectConfiguration(tree, 'mypkg', {
|
||||
root: 'libs/mypkg',
|
||||
sourceRoot: 'libs/mypkg/src',
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@nx/js:tsc',
|
||||
options: {
|
||||
main: 'libs/mypkg/src/custom.ts',
|
||||
outputPath: 'dist/custom',
|
||||
tsConfig: 'libs/mypkg/src/tsconfig.custom.json',
|
||||
additionalEntryPoints: ['libs/mypkg/src/extra.ts'],
|
||||
generateExportsField: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await configurationGenerator(tree, {
|
||||
addPlugin: false,
|
||||
project: 'mypkg',
|
||||
buildTarget: 'build',
|
||||
skipValidation: true,
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'mypkg');
|
||||
|
||||
expect(project.targets).toMatchObject({
|
||||
build: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
main: 'libs/mypkg/src/custom.ts',
|
||||
outputPath: 'dist/custom',
|
||||
tsConfig: 'libs/mypkg/src/tsconfig.custom.json',
|
||||
additionalEntryPoints: ['libs/mypkg/src/extra.ts'],
|
||||
generateExportsField: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -5,7 +5,6 @@ import {
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
@ -31,16 +30,7 @@ describe('configurationGenerator', () => {
|
||||
|
||||
const project = readProjectConfiguration(tree, 'mypkg');
|
||||
|
||||
expect(project.targets).toMatchObject({
|
||||
build: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
defaultConfiguration: 'production',
|
||||
options: {
|
||||
main: 'libs/mypkg/src/main.ts',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(project.targets?.build).toBeUndefined();
|
||||
|
||||
expect(readJson(tree, 'libs/mypkg/package.json')).toEqual({
|
||||
name: '@proj/mypkg',
|
||||
@ -66,82 +56,58 @@ describe('configurationGenerator', () => {
|
||||
it('should support --main option', async () => {
|
||||
await configurationGenerator(tree, {
|
||||
project: 'mypkg',
|
||||
main: 'libs/mypkg/index.ts',
|
||||
main: './src/index.ts',
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'mypkg');
|
||||
const rollupConfig = tree.read('libs/mypkg/rollup.config.js', 'utf-8');
|
||||
|
||||
expect(project.targets).toMatchObject({
|
||||
build: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
defaultConfiguration: 'production',
|
||||
options: {
|
||||
main: 'libs/mypkg/index.ts',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(rollupConfig)
|
||||
.toEqual(`const { withNx } = require('@nx/rollup/with-nx');
|
||||
|
||||
module.exports = withNx(
|
||||
{
|
||||
main: './src/index.ts',
|
||||
outputPath: '../../dist/libs/mypkg',
|
||||
tsConfig: './tsconfig.lib.json',
|
||||
compiler: 'babel',
|
||||
format: ['esm'],
|
||||
assets: [{ input: '.', output: '.', glob: '*.md' }],
|
||||
},
|
||||
{
|
||||
// Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
|
||||
// e.g.
|
||||
// output: { sourcemap: true },
|
||||
}
|
||||
);
|
||||
`);
|
||||
});
|
||||
|
||||
it('should support --tsConfig option', async () => {
|
||||
await configurationGenerator(tree, {
|
||||
project: 'mypkg',
|
||||
tsConfig: 'libs/mypkg/tsconfig.custom.json',
|
||||
tsConfig: './tsconfig.custom.json',
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'mypkg');
|
||||
const rollupConfig = tree.read('libs/mypkg/rollup.config.js', 'utf-8');
|
||||
|
||||
expect(project.targets).toMatchObject({
|
||||
build: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
defaultConfiguration: 'production',
|
||||
options: {
|
||||
tsConfig: 'libs/mypkg/tsconfig.custom.json',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
expect(rollupConfig)
|
||||
.toEqual(`const { withNx } = require('@nx/rollup/with-nx');
|
||||
|
||||
it('should carry over known executor options from existing build target', async () => {
|
||||
updateProjectConfiguration(tree, 'mypkg', {
|
||||
root: 'libs/mypkg',
|
||||
sourceRoot: 'libs/mypkg/src',
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@nx/js:tsc',
|
||||
options: {
|
||||
main: 'libs/mypkg/src/custom.ts',
|
||||
outputPath: 'dist/custom',
|
||||
tsConfig: 'libs/mypkg/src/tsconfig.custom.json',
|
||||
additionalEntryPoints: ['libs/mypkg/src/extra.ts'],
|
||||
generateExportsField: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await configurationGenerator(tree, {
|
||||
project: 'mypkg',
|
||||
buildTarget: 'build',
|
||||
skipValidation: true,
|
||||
});
|
||||
|
||||
const project = readProjectConfiguration(tree, 'mypkg');
|
||||
|
||||
expect(project.targets).toMatchObject({
|
||||
build: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
defaultConfiguration: 'production',
|
||||
options: {
|
||||
main: 'libs/mypkg/src/custom.ts',
|
||||
outputPath: 'dist/custom',
|
||||
tsConfig: 'libs/mypkg/src/tsconfig.custom.json',
|
||||
additionalEntryPoints: ['libs/mypkg/src/extra.ts'],
|
||||
generateExportsField: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
module.exports = withNx(
|
||||
{
|
||||
main: './src/index.ts',
|
||||
outputPath: '../../dist/libs/mypkg',
|
||||
tsConfig: './tsconfig.custom.json',
|
||||
compiler: 'babel',
|
||||
format: ['esm'],
|
||||
assets: [{ input: '.', output: '.', glob: '*.md' }],
|
||||
},
|
||||
{
|
||||
// Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
|
||||
// e.g.
|
||||
// output: { sourcemap: true },
|
||||
}
|
||||
);
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
import {
|
||||
formatFiles,
|
||||
joinPathFragments,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
GeneratorCallback,
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
runTasksInSerial,
|
||||
stripIndents,
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
@ -15,20 +18,35 @@ import { RollupExecutorOptions } from '../../executors/rollup/schema';
|
||||
import { RollupProjectSchema } from './schema';
|
||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/add-build-target-defaults';
|
||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||
import { hasPlugin } from '../../utils/has-plugin';
|
||||
import { RollupWithNxPluginOptions } from '../../plugins/with-nx/with-nx-options';
|
||||
|
||||
export async function configurationGenerator(
|
||||
tree: Tree,
|
||||
options: RollupProjectSchema
|
||||
) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const nxJson = readNxJson(tree);
|
||||
const addPluginDefault =
|
||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false;
|
||||
options.addPlugin ??= addPluginDefault;
|
||||
|
||||
tasks.push(await rollupInitGenerator(tree, { ...options, skipFormat: true }));
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
tasks.push(ensureDependencies(tree, options));
|
||||
}
|
||||
|
||||
options.buildTarget ??= 'build';
|
||||
checkForTargetConflicts(tree, options);
|
||||
addBuildTarget(tree, options);
|
||||
if (hasPlugin(tree)) {
|
||||
createRollupConfig(tree, options);
|
||||
} else {
|
||||
options.buildTarget ??= 'build';
|
||||
checkForTargetConflicts(tree, options);
|
||||
addBuildTarget(tree, options);
|
||||
}
|
||||
|
||||
addPackageJson(tree, options);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
@ -37,6 +55,39 @@ export async function configurationGenerator(
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
function createRollupConfig(tree: Tree, options: RollupProjectSchema) {
|
||||
const project = readProjectConfiguration(tree, options.project);
|
||||
const buildOptions: RollupWithNxPluginOptions = {
|
||||
outputPath: joinPathFragments(
|
||||
offsetFromRoot(project.root),
|
||||
'dist',
|
||||
project.root === '.' ? project.name : project.root
|
||||
),
|
||||
compiler: options.compiler ?? 'babel',
|
||||
main: options.main ?? './src/index.ts',
|
||||
tsConfig: options.tsConfig ?? './tsconfig.lib.json',
|
||||
};
|
||||
|
||||
tree.write(
|
||||
joinPathFragments(project.root, 'rollup.config.js'),
|
||||
stripIndents`
|
||||
const { withNx } = require('@nx/rollup/with-nx');
|
||||
|
||||
module.exports = withNx({
|
||||
main: '${buildOptions.main}',
|
||||
outputPath: '${buildOptions.outputPath}',
|
||||
tsConfig: '${buildOptions.tsConfig}',
|
||||
compiler: '${buildOptions.compiler}',
|
||||
format: ${JSON.stringify(options.format ?? ['esm'])},
|
||||
assets:[{ input: '.', output: '.', glob:'*.md'}],
|
||||
}, {
|
||||
// Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
|
||||
// e.g.
|
||||
// output: { sourcemap: true },
|
||||
});`
|
||||
);
|
||||
}
|
||||
|
||||
function checkForTargetConflicts(tree: Tree, options: RollupProjectSchema) {
|
||||
if (options.skipValidation) return;
|
||||
const project = readProjectConfiguration(tree, options.project);
|
||||
@ -47,8 +98,7 @@ function checkForTargetConflicts(tree: Tree, options: RollupProjectSchema) {
|
||||
}
|
||||
}
|
||||
|
||||
function addBuildTarget(tree: Tree, options: RollupProjectSchema) {
|
||||
addBuildTargetDefaults(tree, '@nx/rollup:rollup', options.buildTarget);
|
||||
function addPackageJson(tree: Tree, options: RollupProjectSchema) {
|
||||
const project = readProjectConfiguration(tree, options.project);
|
||||
const packageJsonPath = joinPathFragments(project.root, 'package.json');
|
||||
|
||||
@ -60,14 +110,18 @@ function addBuildTarget(tree: Tree, options: RollupProjectSchema) {
|
||||
version: '0.0.1',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addBuildTarget(tree: Tree, options: RollupProjectSchema) {
|
||||
addBuildTargetDefaults(tree, '@nx/rollup:rollup', options.buildTarget);
|
||||
const project = readProjectConfiguration(tree, options.project);
|
||||
const prevBuildOptions = project.targets?.[options.buildTarget]?.options;
|
||||
|
||||
const buildOptions: RollupExecutorOptions = {
|
||||
main:
|
||||
options.main ??
|
||||
prevBuildOptions?.main ??
|
||||
joinPathFragments(project.root, 'src/main.ts'),
|
||||
joinPathFragments(project.root, 'src/index.ts'),
|
||||
outputPath:
|
||||
prevBuildOptions?.outputPath ??
|
||||
joinPathFragments(
|
||||
@ -107,17 +161,7 @@ function addBuildTarget(tree: Tree, options: RollupProjectSchema) {
|
||||
[options.buildTarget]: {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
defaultConfiguration: 'production',
|
||||
options: buildOptions,
|
||||
configurations: {
|
||||
production: {
|
||||
optimization: true,
|
||||
sourceMap: false,
|
||||
namedChunks: false,
|
||||
extractLicenses: true,
|
||||
vendorChunk: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -11,4 +11,5 @@ export interface RollupProjectSchema {
|
||||
rollupConfig?: string;
|
||||
buildTarget?: string;
|
||||
format?: ('cjs' | 'esm')[];
|
||||
addPlugin?: boolean;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import 'nx/src/internal-testing-utils/mock-project-graph';
|
||||
|
||||
import { Tree, readJson, ProjectGraph } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { nxVersion, rollupVersion } from '../../utils/versions';
|
||||
|
||||
import { rollupInitGenerator } from './init';
|
||||
|
||||
@ -32,7 +32,7 @@ describe('rollupInitGenerator', () => {
|
||||
expect(packageJson).toEqual({
|
||||
name: expect.any(String),
|
||||
dependencies: {},
|
||||
devDependencies: { '@nx/rollup': nxVersion },
|
||||
devDependencies: { '@nx/rollup': nxVersion, rollup: rollupVersion },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,25 +5,30 @@ import {
|
||||
GeneratorCallback,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { nxVersion, rollupVersion } from '../../utils/versions';
|
||||
import { Schema } from './schema';
|
||||
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
||||
import { createNodes } from '../../plugins/plugin';
|
||||
|
||||
export async function rollupInitGenerator(tree: Tree, schema: Schema) {
|
||||
let task: GeneratorCallback = () => {};
|
||||
schema.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false';
|
||||
|
||||
if (!schema.skipPackageJson) {
|
||||
const devDependencies = { '@nx/rollup': nxVersion };
|
||||
if (schema.addPlugin) {
|
||||
// Ensure user can run Rollup CLI.
|
||||
devDependencies['rollup'] = rollupVersion;
|
||||
}
|
||||
task = addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{ '@nx/rollup': nxVersion },
|
||||
devDependencies,
|
||||
undefined,
|
||||
schema.keepExistingVersions
|
||||
);
|
||||
}
|
||||
|
||||
schema.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false';
|
||||
if (schema.addPlugin) {
|
||||
await addPluginV1(
|
||||
tree,
|
||||
|
||||
14
packages/rollup/src/plugins/delete-output.ts
Normal file
14
packages/rollup/src/plugins/delete-output.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import type { Plugin } from 'rollup';
|
||||
import { deleteOutputDir } from '../utils/fs';
|
||||
|
||||
export interface DeleteOutputOptions {
|
||||
dirs: string[];
|
||||
}
|
||||
|
||||
export function deleteOutput(options: DeleteOutputOptions): Plugin {
|
||||
return {
|
||||
name: 'rollup-plugin-nx-delete-output',
|
||||
buildStart: () =>
|
||||
options.dirs.forEach((dir) => deleteOutputDir(process.cwd(), dir)),
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import type { Plugin } from 'rollup';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { updatePackageJson } from './update-package-json';
|
||||
|
||||
export interface GeneratePackageJsonOptions {
|
||||
outputPath: string;
|
||||
main: string;
|
||||
format: string[];
|
||||
generateExportsField?: boolean;
|
||||
skipTypeField?: boolean;
|
||||
outputFileName?: string;
|
||||
additionalEntryPoints?: string[];
|
||||
}
|
||||
|
||||
export function generatePackageJson(
|
||||
options: GeneratePackageJsonOptions,
|
||||
packageJson: PackageJson
|
||||
): Plugin {
|
||||
return {
|
||||
name: 'rollup-plugin-nx-generate-package-json',
|
||||
writeBundle: () => {
|
||||
updatePackageJson(options, packageJson);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -2,12 +2,18 @@ import { basename, join, parse } from 'path';
|
||||
import { writeJsonFile } from 'nx/src/utils/fileutils';
|
||||
import { writeFileSync } from 'fs';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { NormalizedRollupExecutorOptions } from './normalize';
|
||||
import { stripIndents } from '@nx/devkit';
|
||||
import { stripIndents, workspaceRoot } from '@nx/devkit';
|
||||
|
||||
// TODO(jack): Use updatePackageJson from @nx/js instead.
|
||||
export function updatePackageJson(
|
||||
options: NormalizedRollupExecutorOptions,
|
||||
options: {
|
||||
outputPath: string;
|
||||
main: string;
|
||||
format: string[];
|
||||
generateExportsField?: boolean;
|
||||
skipTypeField?: boolean;
|
||||
outputFileName?: string;
|
||||
additionalEntryPoints?: string[];
|
||||
},
|
||||
packageJson: PackageJson
|
||||
) {
|
||||
const hasEsmFormat = options.format.includes('esm');
|
||||
@ -72,13 +78,14 @@ export function updatePackageJson(
|
||||
// default import in Node will not work.
|
||||
writeFileSync(
|
||||
join(
|
||||
workspaceRoot,
|
||||
options.outputPath,
|
||||
filePath.replace(/\.cjs\.js$/, '.cjs.default.js')
|
||||
),
|
||||
`exports._default = require('./${parse(filePath).base}').default;`
|
||||
);
|
||||
writeFileSync(
|
||||
join(options.outputPath, fauxEsmFilePath),
|
||||
join(workspaceRoot, options.outputPath, fauxEsmFilePath),
|
||||
// Re-export from relative CJS file, and Node will synthetically export it as ESM.
|
||||
stripIndents`
|
||||
export * from './${relativeFile}';
|
||||
@ -95,29 +102,31 @@ export function updatePackageJson(
|
||||
}
|
||||
}
|
||||
|
||||
writeJsonFile(`${options.outputPath}/package.json`, packageJson);
|
||||
writeJsonFile(
|
||||
join(workspaceRoot, options.outputPath, 'package.json'),
|
||||
packageJson
|
||||
);
|
||||
}
|
||||
|
||||
interface Exports {
|
||||
'.': string;
|
||||
|
||||
[name: string]: string;
|
||||
}
|
||||
|
||||
function getExports(
|
||||
options: Pick<
|
||||
NormalizedRollupExecutorOptions,
|
||||
'main' | 'projectRoot' | 'outputFileName' | 'additionalEntryPoints'
|
||||
> & {
|
||||
fileExt: string;
|
||||
function getExports(options: {
|
||||
main?: string;
|
||||
fileExt: string;
|
||||
outputFileName?: string;
|
||||
additionalEntryPoints?: string[];
|
||||
}): Exports {
|
||||
const exports: Exports = {};
|
||||
|
||||
// Users may provide custom input option and skip the main field.
|
||||
if (options.main) {
|
||||
const mainFile = options.outputFileName
|
||||
? options.outputFileName.replace(/\.[tj]s$/, '')
|
||||
: basename(options.main).replace(/\.[tj]s$/, '');
|
||||
exports['.'] = './' + mainFile + options.fileExt;
|
||||
}
|
||||
): Exports {
|
||||
const mainFile = options.outputFileName
|
||||
? options.outputFileName.replace(/\.[tj]s$/, '')
|
||||
: basename(options.main).replace(/\.[tj]s$/, '');
|
||||
const exports: Exports = {
|
||||
'.': './' + mainFile + options.fileExt,
|
||||
};
|
||||
|
||||
if (options.additionalEntryPoints) {
|
||||
for (const file of options.additionalEntryPoints) {
|
||||
18
packages/rollup/src/plugins/with-nx/get-project-node.ts
Normal file
18
packages/rollup/src/plugins/with-nx/get-project-node.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { ProjectGraphProjectNode, readCachedProjectGraph } from '@nx/devkit';
|
||||
|
||||
export function getProjectNode(): ProjectGraphProjectNode {
|
||||
// During graph construction, project is not necessary. Return a stub.
|
||||
if (global.NX_GRAPH_CREATION) {
|
||||
return {
|
||||
type: 'lib',
|
||||
name: '',
|
||||
data: {
|
||||
root: '',
|
||||
},
|
||||
};
|
||||
} else {
|
||||
const projectGraph = readCachedProjectGraph();
|
||||
const projectName = process.env.NX_TASK_TARGET_PROJECT;
|
||||
return projectGraph.nodes[projectName];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
import { normalizeOptions } from './normalize-options';
|
||||
|
||||
jest.mock('@nx/js', () => ({
|
||||
...jest.requireActual('@nx/js'),
|
||||
createEntryPoints: (x: string) => x,
|
||||
}));
|
||||
|
||||
jest.mock('@nx/devkit', () => ({
|
||||
...jest.requireActual('@nx/devkit'),
|
||||
workspaceRoot: '/tmp',
|
||||
}));
|
||||
|
||||
jest.mock('node:fs', () => ({
|
||||
statSync: () => ({ isDirectory: () => true }),
|
||||
}));
|
||||
|
||||
describe('normalizeOptions', () => {
|
||||
it('should provide defaults', () => {
|
||||
const result = normalizeOptions('pkg', 'pkg', {
|
||||
main: './src/main.ts',
|
||||
tsConfig: './tsconfig.json',
|
||||
outputPath: '../dist/pkg',
|
||||
});
|
||||
|
||||
expect(result).toMatchObject({
|
||||
allowJs: false,
|
||||
assets: [],
|
||||
babelUpwardRootMode: false,
|
||||
compiler: 'babel',
|
||||
deleteOutputPath: true,
|
||||
extractCss: true,
|
||||
generateExportsField: false,
|
||||
javascriptEnabled: false,
|
||||
skipTypeCheck: false,
|
||||
skipTypeField: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('should normalize relative paths', () => {
|
||||
const result = normalizeOptions('pkg', 'pkg', {
|
||||
main: './src/main.ts',
|
||||
additionalEntryPoints: ['./src/worker1.ts', './src/worker2.ts'],
|
||||
tsConfig: './tsconfig.json',
|
||||
outputPath: '../dist/pkg',
|
||||
});
|
||||
|
||||
expect(result).toMatchObject({
|
||||
additionalEntryPoints: ['pkg/src/worker1.ts', 'pkg/src/worker2.ts'],
|
||||
main: 'pkg/src/main.ts',
|
||||
outputPath: 'dist/pkg',
|
||||
tsConfig: 'pkg/tsconfig.json',
|
||||
});
|
||||
});
|
||||
|
||||
it('should normalize relative paths', () => {
|
||||
const result = normalizeOptions('pkg', 'pkg', {
|
||||
main: './src/main.ts',
|
||||
tsConfig: './tsconfig.json',
|
||||
outputPath: '../dist/pkg',
|
||||
assets: [
|
||||
'./src/assets',
|
||||
{ input: './docs', output: '.', glob: '**/*.md' },
|
||||
],
|
||||
});
|
||||
|
||||
expect(result).toMatchObject({
|
||||
assets: [
|
||||
{
|
||||
glob: '**/*',
|
||||
input: '/tmp/pkg/src/assets',
|
||||
output: 'src/assets',
|
||||
},
|
||||
{
|
||||
glob: '**/*.md',
|
||||
input: '/tmp/docs',
|
||||
output: '.',
|
||||
},
|
||||
],
|
||||
compiler: 'babel',
|
||||
main: 'pkg/src/main.ts',
|
||||
outputPath: 'dist/pkg',
|
||||
tsConfig: 'pkg/tsconfig.json',
|
||||
});
|
||||
});
|
||||
});
|
||||
107
packages/rollup/src/plugins/with-nx/normalize-options.ts
Normal file
107
packages/rollup/src/plugins/with-nx/normalize-options.ts
Normal file
@ -0,0 +1,107 @@
|
||||
import { basename, dirname, join, relative, resolve } from 'node:path';
|
||||
import { statSync } from 'node:fs';
|
||||
import { normalizePath, workspaceRoot } from '@nx/devkit';
|
||||
import type {
|
||||
AssetGlobPattern,
|
||||
NormalizedRollupWithNxPluginOptions,
|
||||
RollupWithNxPluginOptions,
|
||||
} from './with-nx-options';
|
||||
import { createEntryPoints } from '@nx/js';
|
||||
|
||||
export function normalizeOptions(
|
||||
projectRoot: string,
|
||||
sourceRoot: string,
|
||||
options: RollupWithNxPluginOptions
|
||||
): NormalizedRollupWithNxPluginOptions {
|
||||
if (global.NX_GRAPH_CREATION)
|
||||
return options as NormalizedRollupWithNxPluginOptions;
|
||||
normalizeRelativePaths(projectRoot, options);
|
||||
return {
|
||||
...options,
|
||||
additionalEntryPoints: createEntryPoints(
|
||||
options.additionalEntryPoints,
|
||||
workspaceRoot
|
||||
),
|
||||
allowJs: options.allowJs ?? false,
|
||||
assets: options.assets
|
||||
? normalizeAssets(options.assets, workspaceRoot, sourceRoot)
|
||||
: [],
|
||||
babelUpwardRootMode: options.babelUpwardRootMode ?? false,
|
||||
compiler: options.compiler ?? 'babel',
|
||||
deleteOutputPath: options.deleteOutputPath ?? true,
|
||||
extractCss: options.extractCss ?? true,
|
||||
format: options.format ? Array.from(new Set(options.format)) : undefined,
|
||||
generateExportsField: options.generateExportsField ?? false,
|
||||
javascriptEnabled: options.javascriptEnabled ?? false,
|
||||
skipTypeCheck: options.skipTypeCheck ?? false,
|
||||
skipTypeField: options.skipTypeField ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeAssets(
|
||||
assets: any[],
|
||||
root: string,
|
||||
sourceRoot: string
|
||||
): AssetGlobPattern[] {
|
||||
return assets.map((asset) => {
|
||||
if (typeof asset === 'string') {
|
||||
const assetPath = normalizePath(asset);
|
||||
const resolvedAssetPath = resolve(root, assetPath);
|
||||
const resolvedSourceRoot = resolve(root, sourceRoot);
|
||||
|
||||
if (!resolvedAssetPath.startsWith(resolvedSourceRoot)) {
|
||||
throw new Error(
|
||||
`The ${resolvedAssetPath} asset path must start with the project source root: ${sourceRoot}`
|
||||
);
|
||||
}
|
||||
|
||||
const isDirectory = statSync(resolvedAssetPath).isDirectory();
|
||||
const input = isDirectory
|
||||
? resolvedAssetPath
|
||||
: dirname(resolvedAssetPath);
|
||||
const output = relative(resolvedSourceRoot, resolve(root, input));
|
||||
const glob = isDirectory ? '**/*' : basename(resolvedAssetPath);
|
||||
return {
|
||||
input,
|
||||
output,
|
||||
glob,
|
||||
};
|
||||
} else {
|
||||
if (asset.output.startsWith('..')) {
|
||||
throw new Error(
|
||||
'An asset cannot be written to a location outside of the output path.'
|
||||
);
|
||||
}
|
||||
|
||||
const assetPath = normalizePath(asset.input);
|
||||
const resolvedAssetPath = resolve(root, assetPath);
|
||||
return {
|
||||
...asset,
|
||||
input: resolvedAssetPath,
|
||||
// Now we remove starting slash to make Webpack place it from the output root.
|
||||
output: asset.output.replace(/^\//, ''),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeRelativePaths(
|
||||
projectRoot: string,
|
||||
options: RollupWithNxPluginOptions
|
||||
): void {
|
||||
for (const [fieldName, fieldValue] of Object.entries(options)) {
|
||||
if (isRelativePath(fieldValue)) {
|
||||
options[fieldName] = join(projectRoot, fieldValue);
|
||||
} else if (Array.isArray(fieldValue)) {
|
||||
for (let i = 0; i < fieldValue.length; i++) {
|
||||
if (isRelativePath(fieldValue[i])) {
|
||||
fieldValue[i] = join(projectRoot, fieldValue[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isRelativePath(val: unknown): boolean {
|
||||
return typeof val === 'string' && val.startsWith('.');
|
||||
}
|
||||
37
packages/rollup/src/plugins/with-nx/with-nx-options.ts
Normal file
37
packages/rollup/src/plugins/with-nx/with-nx-options.ts
Normal file
@ -0,0 +1,37 @@
|
||||
// TODO: Add TSDoc
|
||||
export interface RollupWithNxPluginOptions {
|
||||
additionalEntryPoints?: string[];
|
||||
allowJs?: boolean;
|
||||
assets?: any[];
|
||||
babelUpwardRootMode?: boolean;
|
||||
compiler?: 'babel' | 'tsc' | 'swc';
|
||||
deleteOutputPath?: boolean;
|
||||
external?: string[] | 'all' | 'none';
|
||||
extractCss?: boolean | string;
|
||||
format?: ('cjs' | 'esm')[];
|
||||
generateExportsField?: boolean;
|
||||
javascriptEnabled?: boolean;
|
||||
main: string;
|
||||
/** @deprecated Do not set this. The package.json file in project root is detected automatically. */
|
||||
project?: string;
|
||||
outputFileName?: string;
|
||||
outputPath: string;
|
||||
rollupConfig?: string | string[];
|
||||
skipTypeCheck?: boolean;
|
||||
skipTypeField?: boolean;
|
||||
tsConfig: string;
|
||||
}
|
||||
|
||||
export interface AssetGlobPattern {
|
||||
glob: string;
|
||||
ignore?: string[];
|
||||
input: string;
|
||||
output: string;
|
||||
}
|
||||
|
||||
export interface NormalizedRollupWithNxPluginOptions
|
||||
extends RollupWithNxPluginOptions {
|
||||
assets: AssetGlobPattern[];
|
||||
compiler: 'babel' | 'tsc' | 'swc';
|
||||
format: ('cjs' | 'esm')[];
|
||||
}
|
||||
333
packages/rollup/src/plugins/with-nx/with-nx.ts
Normal file
333
packages/rollup/src/plugins/with-nx/with-nx.ts
Normal file
@ -0,0 +1,333 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
import { dirname, join, parse } from 'node:path';
|
||||
import * as ts from 'typescript';
|
||||
import * as rollup from 'rollup';
|
||||
import { getBabelInputPlugin } from '@rollup/plugin-babel';
|
||||
import * as autoprefixer from 'autoprefixer';
|
||||
import {
|
||||
joinPathFragments,
|
||||
logger,
|
||||
type ProjectGraph,
|
||||
readCachedProjectGraph,
|
||||
readJsonFile,
|
||||
workspaceRoot,
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
calculateProjectBuildableDependencies,
|
||||
computeCompilerOptionsPaths,
|
||||
DependentBuildableProjectNode,
|
||||
} from '@nx/js/src/utils/buildable-libs-utils';
|
||||
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||
import { typeDefinitions } from '@nx/js/src/plugins/rollup/type-definitions';
|
||||
|
||||
import { analyze } from '../analyze';
|
||||
import { swc } from '../swc';
|
||||
import { generatePackageJson } from '../package-json/generate-package-json';
|
||||
import { getProjectNode } from './get-project-node';
|
||||
import { deleteOutput } from '../delete-output';
|
||||
import { AssetGlobPattern, RollupWithNxPluginOptions } from './with-nx-options';
|
||||
import { normalizeOptions } from './normalize-options';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
// These use require because the ES import isn't correct.
|
||||
const commonjs = require('@rollup/plugin-commonjs');
|
||||
const image = require('@rollup/plugin-image');
|
||||
|
||||
const json = require('@rollup/plugin-json');
|
||||
const copy = require('rollup-plugin-copy');
|
||||
const postcss = require('rollup-plugin-postcss');
|
||||
|
||||
const fileExtensions = ['.js', '.jsx', '.ts', '.tsx'];
|
||||
|
||||
export function withNx(
|
||||
rawOptions: RollupWithNxPluginOptions,
|
||||
rollupConfig: rollup.RollupOptions = {},
|
||||
// Passed by @nx/rollup:rollup executor to previous behavior of remapping tsconfig paths based on buildable dependencies remains intact.
|
||||
dependencies?: DependentBuildableProjectNode[]
|
||||
): rollup.RollupOptions {
|
||||
const finalConfig: rollup.RollupOptions = { ...rollupConfig };
|
||||
|
||||
// Since this is invoked by the executor, the graph has already been created and cached.
|
||||
const projectNode = getProjectNode();
|
||||
const projectRoot = join(workspaceRoot, projectNode.data.root);
|
||||
|
||||
// Cannot read in graph during construction, but we only need it during build time.
|
||||
const projectGraph: ProjectGraph | null = global.NX_GRAPH_CREATION
|
||||
? null
|
||||
: readCachedProjectGraph();
|
||||
|
||||
// If dependencies are not passed from executor, calculate them from project graph.
|
||||
if (!dependencies && !global.NX_GRAPH_CREATION) {
|
||||
const result = calculateProjectBuildableDependencies(
|
||||
undefined,
|
||||
projectGraph,
|
||||
workspaceRoot,
|
||||
projectNode.name,
|
||||
process.env.NX_TASK_TARGET_TARGET,
|
||||
process.env.NX_TASK_TARGET_CONFIGURATION,
|
||||
true
|
||||
);
|
||||
dependencies = result.dependencies;
|
||||
}
|
||||
|
||||
const options = normalizeOptions(
|
||||
projectNode.data.root,
|
||||
projectNode.data.sourceRoot,
|
||||
rawOptions
|
||||
);
|
||||
|
||||
const useBabel = options.compiler === 'babel';
|
||||
const useSwc = options.compiler === 'swc';
|
||||
|
||||
const tsConfigPath = joinPathFragments(workspaceRoot, options.tsConfig);
|
||||
const tsConfigFile = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
|
||||
const tsConfig = ts.parseJsonConfigFileContent(
|
||||
tsConfigFile.config,
|
||||
ts.sys,
|
||||
dirname(tsConfigPath)
|
||||
);
|
||||
|
||||
if (!options.format || !options.format.length) {
|
||||
options.format = readCompatibleFormats(tsConfig);
|
||||
}
|
||||
|
||||
if (
|
||||
rollupConfig.input &&
|
||||
(options.main || options.additionalEntryPoints.length > 0)
|
||||
) {
|
||||
logger.warn(
|
||||
`Setting "input" in rollup config overrides "main" and "additionalEntryPoints" options.`
|
||||
);
|
||||
}
|
||||
|
||||
// If user provides their own input, override our defaults.
|
||||
finalConfig.input = rollupConfig.input || createInput(options);
|
||||
|
||||
if (options.format) {
|
||||
if (Array.isArray(rollupConfig.output)) {
|
||||
throw new Error(
|
||||
`Cannot use Rollup array output option and withNx format option together. Use an object instead.`
|
||||
);
|
||||
}
|
||||
if (rollupConfig.output?.format || rollupConfig.output?.dir) {
|
||||
logger.warn(
|
||||
`"output.dir" and "output.format" are overridden by "withNx".`
|
||||
);
|
||||
}
|
||||
|
||||
finalConfig.output = options.format.map((format) => ({
|
||||
// These options could be overridden by the user, especially if they use a single format.
|
||||
entryFileNames: `[name].${format}.js`,
|
||||
chunkFileNames: `[name].${format}.js`,
|
||||
...rollupConfig.output,
|
||||
// Format and dir cannot be overridden by user or else the behavior will break.
|
||||
format,
|
||||
dir: global.NX_GRAPH_CREATION
|
||||
? // Options are not normalized with project root during graph creation due to the lack of project and project root.
|
||||
// Cannot be joined with workspace root now, but will be handled by @nx/rollup/plugin.
|
||||
options.outputPath
|
||||
: join(workspaceRoot, options.outputPath),
|
||||
}));
|
||||
}
|
||||
|
||||
let packageJson: PackageJson;
|
||||
if (!global.NX_GRAPH_CREATION) {
|
||||
const packageJsonPath = options.project
|
||||
? join(workspaceRoot, options.project)
|
||||
: join(projectRoot, 'package.json');
|
||||
if (!existsSync(packageJsonPath)) {
|
||||
throw new Error(`Cannot find ${packageJsonPath}.`);
|
||||
}
|
||||
|
||||
packageJson = readJsonFile(packageJsonPath);
|
||||
|
||||
if (packageJson.type === 'module') {
|
||||
if (options.format.includes('cjs')) {
|
||||
logger.warn(
|
||||
`Package type is set to "module" but "cjs" format is included. Going to use "esm" format instead. You can change the package type to "commonjs" or remove type in the package.json file.`
|
||||
);
|
||||
}
|
||||
options.format = ['esm'];
|
||||
} else if (packageJson.type === 'commonjs') {
|
||||
if (options.format.includes('esm')) {
|
||||
logger.warn(
|
||||
`Package type is set to "commonjs" but "esm" format is included. Going to use "cjs" format instead. You can change the package type to "module" or remove type in the package.json file.`
|
||||
);
|
||||
}
|
||||
options.format = ['cjs'];
|
||||
}
|
||||
}
|
||||
|
||||
// User may wish to customize how external behaves by overriding our default.
|
||||
if (!rollupConfig.external && !global.NX_GRAPH_CREATION) {
|
||||
const npmDeps = (projectGraph.dependencies[projectNode.name] ?? [])
|
||||
.filter((d) => d.target.startsWith('npm:'))
|
||||
.map((d) => d.target.slice(4));
|
||||
let externalPackages = [
|
||||
...Object.keys(packageJson.dependencies || {}),
|
||||
...Object.keys(packageJson.peerDependencies || {}),
|
||||
]; // If external is set to none, include all dependencies and peerDependencies in externalPackages
|
||||
if (options.external === 'all') {
|
||||
externalPackages = externalPackages.concat(npmDeps);
|
||||
} else if (Array.isArray(options.external) && options.external.length > 0) {
|
||||
externalPackages = externalPackages.concat(options.external);
|
||||
}
|
||||
externalPackages = [...new Set(externalPackages)];
|
||||
finalConfig.external = (id: string) => {
|
||||
return externalPackages.some(
|
||||
(name) => id === name || id.startsWith(`${name}/`)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
if (!global.NX_GRAPH_CREATION) {
|
||||
finalConfig.plugins = [
|
||||
copy({
|
||||
targets: convertCopyAssetsToRollupOptions(
|
||||
options.outputPath,
|
||||
options.assets
|
||||
),
|
||||
}),
|
||||
image(),
|
||||
json(),
|
||||
// Needed to generate type definitions, even if we're using babel or swc.
|
||||
require('rollup-plugin-typescript2')({
|
||||
check: !options.skipTypeCheck,
|
||||
tsconfig: options.tsConfig,
|
||||
tsconfigOverride: {
|
||||
compilerOptions: createTsCompilerOptions(
|
||||
projectRoot,
|
||||
tsConfig,
|
||||
options,
|
||||
dependencies
|
||||
),
|
||||
},
|
||||
}),
|
||||
typeDefinitions({
|
||||
projectRoot,
|
||||
}),
|
||||
postcss({
|
||||
inject: true,
|
||||
extract: options.extractCss,
|
||||
autoModules: true,
|
||||
plugins: [autoprefixer],
|
||||
use: {
|
||||
less: {
|
||||
javascriptEnabled: options.javascriptEnabled,
|
||||
},
|
||||
},
|
||||
}),
|
||||
nodeResolve({
|
||||
preferBuiltins: true,
|
||||
extensions: fileExtensions,
|
||||
}),
|
||||
useSwc && swc(),
|
||||
useBabel &&
|
||||
getBabelInputPlugin({
|
||||
// Lets `@nx/js/babel` preset know that we are packaging.
|
||||
caller: {
|
||||
// @ts-ignore
|
||||
// Ignoring type checks for caller since we have custom attributes
|
||||
isNxPackage: true,
|
||||
// Always target esnext and let rollup handle cjs
|
||||
supportsStaticESM: true,
|
||||
isModern: true,
|
||||
},
|
||||
cwd: join(
|
||||
workspaceRoot,
|
||||
projectNode.data.sourceRoot ?? projectNode.data.root
|
||||
),
|
||||
rootMode: options.babelUpwardRootMode ? 'upward' : undefined,
|
||||
babelrc: true,
|
||||
extensions: fileExtensions,
|
||||
babelHelpers: 'bundled',
|
||||
skipPreflightCheck: true, // pre-flight check may yield false positives and also slows down the build
|
||||
exclude: /node_modules/,
|
||||
}),
|
||||
commonjs(),
|
||||
analyze(),
|
||||
generatePackageJson(options, packageJson),
|
||||
];
|
||||
if (Array.isArray(rollupConfig.plugins)) {
|
||||
finalConfig.plugins.push(...rollupConfig.plugins);
|
||||
}
|
||||
if (options.deleteOutputPath) {
|
||||
finalConfig.plugins.push(
|
||||
deleteOutput({
|
||||
dirs: Array.isArray(finalConfig.output)
|
||||
? finalConfig.output.map((o) => o.dir)
|
||||
: [finalConfig.output.dir],
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return finalConfig;
|
||||
}
|
||||
|
||||
function createInput(
|
||||
options: RollupWithNxPluginOptions
|
||||
): Record<string, string> {
|
||||
const mainEntryFileName = options.outputFileName || options.main;
|
||||
const input: Record<string, string> = {};
|
||||
input[parse(mainEntryFileName).name] = join(workspaceRoot, options.main);
|
||||
options.additionalEntryPoints?.forEach((entry) => {
|
||||
input[parse(entry).name] = join(workspaceRoot, entry);
|
||||
});
|
||||
return input;
|
||||
}
|
||||
|
||||
function createTsCompilerOptions(
|
||||
projectRoot: string,
|
||||
config: ts.ParsedCommandLine,
|
||||
options: RollupWithNxPluginOptions,
|
||||
dependencies?: DependentBuildableProjectNode[]
|
||||
) {
|
||||
const compilerOptionPaths = computeCompilerOptionsPaths(
|
||||
config,
|
||||
dependencies ?? []
|
||||
);
|
||||
const compilerOptions = {
|
||||
rootDir: projectRoot,
|
||||
allowJs: options.allowJs,
|
||||
declaration: true,
|
||||
paths: compilerOptionPaths,
|
||||
};
|
||||
if (config.options.module === ts.ModuleKind.CommonJS) {
|
||||
compilerOptions['module'] = 'ESNext';
|
||||
}
|
||||
if (options.compiler === 'swc') {
|
||||
compilerOptions['emitDeclarationOnly'] = true;
|
||||
}
|
||||
return compilerOptions;
|
||||
}
|
||||
|
||||
interface RollupCopyAssetOption {
|
||||
src: string;
|
||||
dest: string;
|
||||
}
|
||||
|
||||
function convertCopyAssetsToRollupOptions(
|
||||
outputPath: string,
|
||||
assets: AssetGlobPattern[]
|
||||
): RollupCopyAssetOption[] {
|
||||
return assets
|
||||
? assets.map((a) => ({
|
||||
src: join(a.input, a.glob).replace(/\\/g, '/'),
|
||||
dest: join(workspaceRoot, outputPath, a.output).replace(/\\/g, '/'),
|
||||
}))
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function readCompatibleFormats(
|
||||
config: ts.ParsedCommandLine
|
||||
): ('cjs' | 'esm')[] {
|
||||
switch (config.options.module) {
|
||||
case ts.ModuleKind.CommonJS:
|
||||
case ts.ModuleKind.UMD:
|
||||
case ts.ModuleKind.AMD:
|
||||
return ['cjs'];
|
||||
default:
|
||||
return ['esm'];
|
||||
}
|
||||
}
|
||||
10
packages/rollup/src/utils/has-plugin.ts
Normal file
10
packages/rollup/src/utils/has-plugin.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { readNxJson, Tree } from '@nx/devkit';
|
||||
|
||||
export function hasPlugin(tree: Tree) {
|
||||
const nxJson = readNxJson(tree);
|
||||
return !!nxJson.plugins?.some((p) =>
|
||||
typeof p === 'string'
|
||||
? p === '@nx/rollup/plugin'
|
||||
: p.plugin === '@nx/rollup/plugin'
|
||||
);
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
export const nxVersion = require('../../package.json').version;
|
||||
export const coreJsVersion = '^3.36.1';
|
||||
export const rollupVersion = '^4.14.0';
|
||||
export const swcLoaderVersion = '0.1.15';
|
||||
export const tsLibVersion = '^2.3.0';
|
||||
|
||||
export const coreJsVersion = '^3.36.1';
|
||||
|
||||
2
packages/rollup/with-nx.ts
Normal file
2
packages/rollup/with-nx.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { withNx } from './src/plugins/with-nx/with-nx';
|
||||
export type { RollupWithNxPluginOptions } from './src/plugins/with-nx/with-nx-options';
|
||||
Loading…
x
Reference in New Issue
Block a user