Skip to content

Commit

Permalink
feat(react): add format option for buildable libs (#6753)
Browse files Browse the repository at this point in the history
- Clean up @nrwl/web:package executor
- Combine react package e2e tests to speed up test time
  • Loading branch information
jaysoo authored Aug 19, 2021
1 parent 7496483 commit cddb1ed
Show file tree
Hide file tree
Showing 18 changed files with 638 additions and 293 deletions.
8 changes: 8 additions & 0 deletions docs/angular/api-web/executors/package.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ Type: `boolean`

CSS files will be extracted to the output folder.

### format

Alias(es): f

Type: `array`

Only build the specified comma-separated formats (esm,umd,cjs)

### globals

Type: `object[]`
Expand Down
8 changes: 8 additions & 0 deletions docs/node/api-web/executors/package.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ Type: `boolean`

CSS files will be extracted to the output folder.

### format

Alias(es): f

Type: `array`

Only build the specified comma-separated formats (esm,umd,cjs)

### globals

Type: `object[]`
Expand Down
8 changes: 8 additions & 0 deletions docs/react/api-web/executors/package.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ Type: `boolean`

CSS files will be extracted to the output folder.

### format

Alias(es): f

Type: `array`

Only build the specified comma-separated formats (esm,umd,cjs)

### globals

Type: `object[]`
Expand Down
114 changes: 57 additions & 57 deletions e2e/react/src/react-package.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
newProject,
readFile,
readJson,
rmDist,
runCLI,
uniq,
updateFile,
Expand Down Expand Up @@ -118,9 +119,65 @@ describe('Build React libraries and apps', () => {
return JSON.stringify(json, null, 2);
});
});

afterEach(() => killPorts());

describe('Publishable libraries', () => {
it('should build libraries with and without dependencies', () => {
/*
* 1. Without dependencies
*/
const childLibOutput = runCLI(`build ${childLib}`)
// FIX for windows and OSX where output names might get broken to multipleline
.replace(/\s\s\s││\s\s\s/gm, '');
const childLib2Output = runCLI(`build ${childLib2}`)
// FIX for windows and OSX where output names might get broken to multipleline
.replace(/\s\s\s││\s\s\s/gm, '');

expect(childLibOutput).toContain(`${childLib}.umd.js`);
expect(childLibOutput).toContain(`${childLib}.esm.js`);
expect(childLibOutput).toContain(`Bundle complete: ${childLib}`);

expect(childLib2Output).toContain(`${childLib2}.esm.js`);
expect(childLib2Output).toContain(`${childLib2}.umd.js`);
expect(childLib2Output).toContain(`Bundle complete: ${childLib2}`);

checkFilesExist(`dist/libs/${childLib}/assets/hello.txt`);
checkFilesExist(`dist/libs/${childLib2}/README.md`);

/*
* 2. With dependencies
*/
let parentLibOutput = runCLI(`build ${parentLib}`)
// FIX for windows and OSX where output names might get broken to multipleline
.replace(/\s\s\s││\s\s\s/gm, '');

expect(parentLibOutput).toContain(`${parentLib}.esm.js`);
expect(parentLibOutput).toContain(`${parentLib}.umd.js`);
expect(parentLibOutput).toContain(`Bundle complete: ${parentLib}`);

const jsonFile = readJson(`dist/libs/${parentLib}/package.json`);
expect(jsonFile.peerDependencies).toEqual(
expect.objectContaining({
[`@${proj}/${childLib}`]: '0.0.1',
[`@${proj}/${childLib2}`]: '0.0.1',
})
);

/*
* 3. With dependencies without existing dist
*/
rmDist();

parentLibOutput = runCLI(
`build ${parentLib} --with-deps --skip-nx-cache`
).replace(/\s\s\s││\s\s\s/gm, '');

expect(parentLibOutput).toContain(`Bundle complete: ${parentLib}`);
expect(parentLibOutput).toContain(`Bundle complete: ${childLib}`);
expect(parentLibOutput).toContain(`Bundle complete: ${childLib2}`);
});

it('should preserve the tsconfig target set by user', () => {
// Setup
const myLib = uniq('my-lib');
Expand Down Expand Up @@ -172,53 +229,6 @@ describe('Build React libraries and apps', () => {
expect(content).toContain('function __generator(thisArg, body) {');
});

it('should build the library when it does not have any deps', () => {
const output = runCLI(`build ${childLib}`)
// FIX for windows and OSX where output names might get broken to multipleline
.replace(/\s\s\s││\s\s\s/gm, '');
expect(output).toContain(`${childLib}.esm.js`);
expect(output).toContain(`Bundle complete: ${childLib}`);
checkFilesExist(`dist/libs/${childLib}/assets/hello.txt`);
});

it('should copy the README to dist', () => {
const output = runCLI(`build ${childLib2}`);
expect(output).toContain(`Bundle complete: ${childLib2}`);
checkFilesExist(`dist/libs/${childLib2}/README.md`);
});

it('should properly add references to any dependency into the parent package.json', () => {
const childLibOutput = runCLI(`build ${childLib}`)
// FIX for windows and OSX where output names might get broken to multipleline
.replace(/\s\s\s││\s\s\s/gm, '');
const childLib2Output = runCLI(`build ${childLib2}`)
// FIX for windows and OSX where output names might get broken to multipleline
.replace(/\s\s\s││\s\s\s/gm, '');
const parentLibOutput = runCLI(`build ${parentLib}`)
// FIX for windows and OSX where output names might get broken to multipleline
.replace(/\s\s\s││\s\s\s/gm, '');

expect(childLibOutput).toContain(`${childLib}.esm.js`);
expect(childLibOutput).toContain(`${childLib}.umd.js`);
expect(childLibOutput).toContain(`Bundle complete: ${childLib}`);

expect(childLib2Output).toContain(`${childLib2}.esm.js`);
expect(childLib2Output).toContain(`${childLib2}.umd.js`);
expect(childLib2Output).toContain(`Bundle complete: ${childLib2}`);

expect(parentLibOutput).toContain(`${parentLib}.esm.js`);
expect(parentLibOutput).toContain(`${parentLib}.umd.js`);
expect(parentLibOutput).toContain(`Bundle complete: ${parentLib}`);

const jsonFile = readJson(`dist/libs/${parentLib}/package.json`);
expect(jsonFile.peerDependencies).toEqual(
expect.objectContaining({
[`@${proj}/${childLib}`]: '0.0.1',
[`@${proj}/${childLib2}`]: '0.0.1',
})
);
});

it('should build an app composed out of publishable libs', () => {
const buildWithDeps = runCLI(
`build ${app} --with-deps --buildLibsFromSource=false`
Expand All @@ -235,14 +245,4 @@ describe('Build React libraries and apps', () => {
expect(failedBuild).toContain(`Can't resolve`);
}, 1000000);
});

describe('Buildable libraries', () => {
it('should build dependent libraries', () => {
const parentLibOutput = runCLI(`build ${parentLib} --with-deps`);

expect(parentLibOutput).toContain(`Bundle complete: ${parentLib}`);
expect(parentLibOutput).toContain(`Bundle complete: ${childLib}`);
expect(parentLibOutput).toContain(`Bundle complete: ${childLib2}`);
});
});
});
21 changes: 10 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
"@popperjs/core": "^2.9.2",
"@reduxjs/toolkit": "1.5.0",
"@rollup/plugin-babel": "5.0.2",
"@rollup/plugin-commonjs": "11.0.2",
"@rollup/plugin-image": "2.0.4",
"@rollup/plugin-commonjs": "^20.0.0",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-image": "^2.1.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "7.1.1",
"@rollup/plugin-node-resolve": "^13.0.4",
"@schematics/angular": "~12.1.0",
"@storybook/addon-essentials": "~6.3.0",
"@storybook/addon-knobs": "~6.3.0",
Expand Down Expand Up @@ -114,7 +114,7 @@
"angular": "1.8.0",
"autoprefixer": "^10.2.5",
"babel-jest": "27.0.6",
"caniuse-lite": "^1.0.30001030",
"caniuse-lite": "^1.0.30001251",
"chalk": "4.1.0",
"chokidar": "^3.5.1",
"circular-dependency-plugin": "5.2.0",
Expand Down Expand Up @@ -198,12 +198,11 @@
"react-router-dom": "5.1.2",
"regenerator-runtime": "0.13.7",
"release-it": "^14.11.3",
"rollup": "1.31.1",
"rollup-plugin-copy": "3.3.0",
"rollup-plugin-filesize": "^9.0.0",
"rollup-plugin-local-resolve": "1.0.7",
"rollup-plugin-peer-deps-external": "2.2.2",
"rollup-plugin-postcss": "^4.0.0",
"rollup": "^2.56.2",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-filesize": "^9.1.1",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^4.0.1",
"rollup-plugin-typescript2": "^0.30.0",
"rxjs": "6.6.7",
"rxjs-for-await": "0.0.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/web/babel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ module.exports = function (api: any, options: NxReactBabelPresetOptions = {}) {
// All other options will fail in Jest since Node does not support some ES features
// such as import syntax.
process.env.NODE_ENV === 'test'
? { targets: { node: 'current' } }
? { targets: { node: 'current' }, loose: true }
: {
// Allow importing core-js in entrypoint and use browserlist to select polyfills.
// This is needed for differential loading as well.
Expand Down
21 changes: 10 additions & 11 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,19 @@
"@babel/plugin-transform-runtime": "^7.15.0",
"@babel/runtime": "^7.14.8",
"@babel/preset-typescript": "^7.15.0",
"@rollup/plugin-commonjs": "11.0.2",
"@rollup/plugin-babel": "5.0.2",
"@rollup/plugin-image": "2.0.4",
"@rollup/plugin-commonjs": "^20.0.0",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-image": "^2.1.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "7.1.1",
"@rollup/plugin-node-resolve": "^13.0.4",
"autoprefixer": "^10.2.5",
"babel-loader": "8.1.0",
"babel-plugin-const-enum": "^1.0.1",
"babel-plugin-macros": "^2.8.0",
"babel-plugin-transform-async-to-promises": "^0.8.15",
"babel-plugin-transform-typescript-metadata": "^0.3.1",
"browserslist": "^4.16.6",
"caniuse-lite": "^1.0.30001030",
"caniuse-lite": "^1.0.30001251",
"chalk": "4.1.0",
"chokidar": "^3.5.1",
"circular-dependency-plugin": "5.2.0",
Expand All @@ -80,12 +80,11 @@
"rxjs": "^6.5.4",
"rxjs-for-await": "0.0.2",
"rimraf": "^3.0.2",
"rollup": "1.31.1",
"rollup-plugin-copy": "^3.3.0",
"rollup-plugin-filesize": "^9.0.0",
"rollup-plugin-local-resolve": "^1.0.7",
"rollup-plugin-peer-deps-external": "^2.2.2",
"rollup-plugin-postcss": "^4.0.0",
"rollup": "^2.56.2",
"rollup-plugin-copy": "^3.4.0",
"rollup-plugin-filesize": "^9.1.1",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^4.0.1",
"rollup-plugin-typescript2": "^0.30.0",
"sass": "^1.26.3",
"sass-loader": "8.0.2",
Expand Down
46 changes: 46 additions & 0 deletions packages/web/src/executors/package/lib/normalize.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { normalizePackageOptions } from './normalize';
import { WebPackageOptions } from '../schema';

describe('normalizePackageOptions', () => {
let testOptions: WebPackageOptions;
let root: string;
let sourceRoot: string;

beforeEach(() => {
testOptions = {
outputPath: '/tmp',
project: 'apps/nodeapp/package.json',
entryFile: 'apps/nodeapp/src/main.ts',
tsConfig: 'apps/nodeapp/tsconfig.app.json',
rollupConfig: 'apps/nodeapp/rollup.config',
format: ['esm'],
};
root = '/root';
sourceRoot = 'apps/nodeapp/src';
});

it('should resolve both node modules and relative path for rollupConfig', () => {
let result = normalizePackageOptions(testOptions, root, sourceRoot);
expect(result.rollupConfig).toEqual(['/root/apps/nodeapp/rollup.config']);

result = normalizePackageOptions(
{
...testOptions,
// something that exists in node_modules
rollupConfig: 'react',
},
root,
sourceRoot
);
expect(result.rollupConfig).toHaveLength(1);
expect(result.rollupConfig[0]).toMatch('react');
expect(result.rollupConfig[0]).not.toMatch(root);
});

it('should handle rollupConfig being undefined', () => {
delete testOptions.rollupConfig;

const result = normalizePackageOptions(testOptions, root, sourceRoot);
expect(result.rollupConfig).toEqual([]);
});
});
46 changes: 46 additions & 0 deletions packages/web/src/executors/package/lib/normalize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { dirname } from 'path';

import { AssetGlobPattern } from '../../../utils/types';
import { normalizeAssets, normalizePluginPath } from '../../../utils/normalize';
import { WebPackageOptions } from '../schema';

export interface NormalizedWebPackageOptions extends WebPackageOptions {
entryRoot: string;
projectRoot: string;
assets: AssetGlobPattern[];
rollupConfig: string[];
}

export function normalizePackageOptions(
options: WebPackageOptions,
root: string,
sourceRoot: string
): NormalizedWebPackageOptions {
const entryFile = `${root}/${options.entryFile}`;
const entryRoot = dirname(entryFile);
const project = `${root}/${options.project}`;
const projectRoot = dirname(project);
const outputPath = `${root}/${options.outputPath}`;

if (options.buildableProjectDepsInPackageJsonType == undefined) {
options.buildableProjectDepsInPackageJsonType = 'peerDependencies';
}

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,
entryFile,
entryRoot,
project,
projectRoot,
outputPath,
};
}
Loading

1 comment on commit cddb1ed

@vercel
Copy link

@vercel vercel bot commented on cddb1ed Aug 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.