Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(js): add --includeBabelRc flag for @nrwl/js:library generator (#8793, #8600) #10055

Merged
merged 3 commits into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/generated/packages/js.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
"description": "Do not update tsconfig.json for development experience.",
"default": false
},
"includeBabelRc": {
"type": "boolean",
"description": "Include a .babelrc configuration to compile TypeScript files"
},
nartc marked this conversation as resolved.
Show resolved Hide resolved
"testEnvironment": {
"type": "string",
"enum": ["jsdom", "node"],
Expand Down
22 changes: 22 additions & 0 deletions e2e/js/src/js.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
checkFilesExist,
checkFilesDoNotExist,
newProject,
readFile,
readJson,
Expand Down Expand Up @@ -46,6 +47,16 @@ describe('js e2e', () => {
'match the cache'
);

const packageJson = readJson('package.json');
const devPackageNames = Object.keys(packageJson.devDependencies);
expect(devPackageNames).toContain('@nrwl/web');

const babelRc = readJson(`libs/${lib}/.babelrc`);
expect(babelRc.plugins).toBeUndefined();
expect(babelRc.presets).toStrictEqual([
['@nrwl/web/babel', { useBuiltIns: 'usage' }],
]);

expect(runCLI(`build ${lib}`)).toContain('Done compiling TypeScript files');
checkFilesExist(
`dist/libs/${lib}/README.md`,
Expand Down Expand Up @@ -181,6 +192,8 @@ describe('js e2e', () => {
`dist/libs/${lib}/src/lib/${lib}.d.ts`
);

checkFilesDoNotExist(`libs/${lib}/.babelrc`);

const parentLib = uniq('parentlib');
runCLI(`generate @nrwl/js:lib ${parentLib} --buildable --compiler=swc`);
const parentLibPackageJson = readJson(`libs/${parentLib}/package.json`);
Expand Down Expand Up @@ -220,4 +233,13 @@ describe('js e2e', () => {
expect(output).toContain('1 task(s) it depends on');
expect(output).toContain('Successfully compiled: 2 files with swc');
}, 120000);

it('should not create a `.babelrc` file when creating libs with js executors (--compiler=tsc)', () => {
const lib = uniq('lib');
runCLI(
`generate @nrwl/js:lib ${lib} --compiler=tsc --includeBabelRc=false`
);

checkFilesDoNotExist(`libs/${lib}/.babelrc`);
});
});
113 changes: 113 additions & 0 deletions packages/js/src/generators/library/library.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe('lib', () => {
let tree: Tree;
const defaultOptions: Omit<LibraryGeneratorSchema, 'name'> = {
skipTsConfig: false,
includeBabelRc: false,
unitTestRunner: 'jest',
skipFormat: false,
linter: 'eslint',
Expand Down Expand Up @@ -850,5 +851,117 @@ describe('lib', () => {
expect(tree.exists('tools/scripts/publish.mjs')).toBeTruthy();
});
});

describe('--includeBabelRc', () => {
it('should generate a .babelrc when flag is set to true', async () => {
await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
includeBabelRc: true,
});

expect(tree.exists('libs/my-lib/.babelrc')).toBeTruthy();
});

it('should not generate a .babelrc when flag is set to false', async () => {
await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
includeBabelRc: false,
});

expect(tree.exists('libs/my-lib/.babelrc')).toBeFalsy();
});

it('should not generate a .babelrc when compiler is swc (even if flag is set to true)', async () => {
await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
compiler: 'swc',
includeBabelRc: true,
});

expect(tree.exists('libs/my-lib/.babelrc')).toBeFalsy();
});

it('should generate a .babelrc when flag is set to true (even if there is no `@nrwl/web` plugin installed)', async () => {
updateJson(tree, 'package.json', (json) => {
json.devDependencies = {};
return json;
});

await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
includeBabelRc: true,
});

expect(tree.exists('libs/my-lib/.babelrc')).toBeTruthy();

const babelRc = readJson(tree, 'libs/my-lib/.babelrc');
expect(babelRc).toMatchInlineSnapshot(`
Object {
"presets": Array [
Array [
"@nrwl/web/babel",
Object {
"useBuiltIns": "usage",
},
],
],
}
`);
});

it('should generate a .babelrc when flag is not set and there is a `@nrwl/web` package installed', async () => {
updateJson(tree, 'package.json', (json) => {
json.devDependencies = {
'@nrwl/web': '1.1.1',
'@nrwl/react': '1.1.1',
'@nrwl/next': '1.1.1',
};
return json;
});

await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
includeBabelRc: undefined,
});

expect(tree.exists('libs/my-lib/.babelrc')).toBeTruthy();

const babelRc = readJson(tree, 'libs/my-lib/.babelrc');
expect(babelRc).toMatchInlineSnapshot(`
Object {
"presets": Array [
Array [
"@nrwl/web/babel",
Object {
"useBuiltIns": "usage",
},
],
],
}
`);
});
it('should not generate a .babelrc when flag is not set and there is NOT a `@nrwl/web` package installed', async () => {
updateJson(tree, 'package.json', (json) => {
json.devDependencies = {
'@nrwl/angular': '1.1.1',
'@nrwl/next': '1.1.1',
};
return json;
});

await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
includeBabelRc: undefined,
});

expect(tree.exists('libs/my-lib/.babelrc')).toBeFalsy();
});
});
});
});
40 changes: 39 additions & 1 deletion packages/js/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
toJS,
Tree,
updateJson,
readJson,
writeJson,
} from '@nrwl/devkit';
import { jestProjectGenerator } from '@nrwl/jest';
import { findRootJestPreset } from '@nrwl/jest/src/utils/config/find-root-jest-files';
Expand Down Expand Up @@ -177,6 +179,40 @@ function updateTsConfig(tree: Tree, options: NormalizedSchema) {
});
}

/**
* Currently `@nrwl/js:library` TypeScript files can be compiled by most NX applications scaffolded via the Plugin system. However, `@nrwl/react:app` is an exception that due to its babel configuration, won't transpile external TypeScript files from packages/libs that do not contain a .babelrc.
*
* If a user doesn't explicitly set the flag, to prevent breaking the experience (they see the application failing, and they need to manually add the babelrc themselves), we want to detect whether they have the `@nrwl/web` plugin installed, and generate it automatically for them (even when they do not explicity request it).
*
* You can find more details on why this is necessary here:
* https://github.com/nrwl/nx/pull/10055
*/
function shouldAddBabelRc(tree: Tree, options: NormalizedSchema) {
Copy link
Contributor

Choose a reason for hiding this comment

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

question: what if I have nrwl/web installed and I want to generate a nrwl/js:lib BUT I do not want to have .babelrc generated by explicitly use --includeBabelRc=false?

Thinking of a monorepo with both web and an api

Copy link
Contributor Author

@floroz floroz May 4, 2022

Choose a reason for hiding this comment

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

@nartc good point, I just pushed a refactor and added unit tests to cover that scenario, so that now we correctly handle

  1. user explicitly setting the flag to true
  2. user explicitly setting the flag to false
  3. user not setting the flag

Copy link
Contributor

Choose a reason for hiding this comment

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

You can just remove the default in the schema and it will come through as undefined (as long as the flag isn't in the required array in the schema)

if (typeof options.includeBabelRc === 'undefined') {
const webPluginName = '@nrwl/web';

const packageJson = readJson(tree, 'package.json');

const hasNxWebPlugin = Object.keys(
packageJson.devDependencies as Record<string, string>
).includes(webPluginName);

return hasNxWebPlugin;
}

return options.includeBabelRc;
}

function addBabelRc(tree: Tree, options: NormalizedSchema) {
const filename = '.babelrc';

const babelrc = {
presets: [['@nrwl/web/babel', { useBuiltIns: 'usage' }]],
nartc marked this conversation as resolved.
Show resolved Hide resolved
};

writeJson(tree, join(options.projectRoot, filename), babelrc);
}

function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) {
const { className, name, propertyName } = names(options.name);

Expand All @@ -196,9 +232,11 @@ function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) {
hasUnitTestRunner: options.unitTestRunner !== 'none',
});

if (options.buildable && options.compiler === 'swc') {
if (options.compiler === 'swc') {
addSwcDependencies(tree);
addSwcConfig(tree, options.projectRoot);
} else if (shouldAddBabelRc(tree, options)) {
addBabelRc(tree, options);
nartc marked this conversation as resolved.
Show resolved Hide resolved
}

if (options.unitTestRunner === 'none') {
Expand Down
4 changes: 4 additions & 0 deletions packages/js/src/generators/library/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
"description": "Do not update tsconfig.json for development experience.",
"default": false
},
"includeBabelRc": {
"type": "boolean",
"description": "Include a .babelrc configuration to compile TypeScript files"
},
"testEnvironment": {
"type": "string",
"enum": ["jsdom", "node"],
Expand Down
1 change: 1 addition & 0 deletions packages/js/src/utils/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface LibraryGeneratorSchema {
tags?: string;
simpleModuleName?: boolean;
skipTsConfig?: boolean;
includeBabelRc?: boolean;
unitTestRunner?: 'jest' | 'none';
linter?: Linter;
testEnvironment?: 'jsdom' | 'node';
Expand Down