From 143452065f72b26a6c702dbfa1e200f2404553c1 Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Wed, 30 Nov 2022 11:09:28 -0500 Subject: [PATCH] feat(react): add --bundler=none option for React lib generator if the library is not buildable --- docs/generated/packages/react.json | 10 +- docs/generated/packages/vite.json | 3 +- e2e/react/src/react-misc.test.ts | 48 +++ e2e/react/src/react-package.test.ts | 37 ++- e2e/react/src/react.test.ts | 69 ----- .../library/lib/normalize-options.spec.ts | 30 +- .../library/lib/normalize-options.ts | 4 +- .../src/generators/library/library.spec.ts | 278 ++++++++---------- .../react/src/generators/library/library.ts | 3 - .../react/src/generators/library/schema.d.ts | 2 +- .../react/src/generators/library/schema.json | 6 +- .../storybook-configuration/configuration.ts | 2 +- .../storybook-configuration/schema.json | 4 +- .../generators/configuration/configuration.ts | 11 +- .../src/generators/configuration/schema.json | 3 +- 15 files changed, 254 insertions(+), 256 deletions(-) create mode 100644 e2e/react/src/react-misc.test.ts diff --git a/docs/generated/packages/react.json b/docs/generated/packages/react.json index 91ac6bd4280e7..ff2e44dff0040 100644 --- a/docs/generated/packages/react.json +++ b/docs/generated/packages/react.json @@ -436,9 +436,9 @@ }, "bundler": { "type": "string", - "description": "The bundler to use.", - "enum": ["vite", "rollup"], - "x-prompt": "Which bundler would you like to use to build the library?" + "description": "The bundler to use. Choosing 'none' means this library is not buildable.", + "enum": ["none", "vite", "rollup"], + "x-prompt": "Which bundler would you like to use to build the library? Choose 'none' to skip build setup." }, "compiler": { "type": "string", @@ -735,9 +735,7 @@ }, "bundler": { "description": "The Storybook builder to use.", - "enum": ["vite", "webpack"], - "x-prompt": "Which Storybook builder do you want to use?", - "default": "webpack" + "enum": ["vite", "webpack"] } }, "required": ["name"], diff --git a/docs/generated/packages/vite.json b/docs/generated/packages/vite.json index dd2e86efa126a..8e17f78cfdeaf 100644 --- a/docs/generated/packages/vite.json +++ b/docs/generated/packages/vite.json @@ -68,8 +68,7 @@ "includeLib": { "type": "boolean", "description": "Add a library build option and skip the server option.", - "default": false, - "x-prompt": "Does this project contain a buildable library?" + "hidden": true }, "uiFramework": { "type": "string", diff --git a/e2e/react/src/react-misc.test.ts b/e2e/react/src/react-misc.test.ts new file mode 100644 index 0000000000000..5ff8c7a4fe65e --- /dev/null +++ b/e2e/react/src/react-misc.test.ts @@ -0,0 +1,48 @@ +import { + checkFilesExist, + newProject, + runCLI, + runCLIAsync, + uniq, +} from '@nrwl/e2e/utils'; + +describe('React Applications: additional packages', () => { + beforeAll(() => newProject()); + + it('should generate app with routing', async () => { + const appName = uniq('app'); + + runCLI( + `generate @nrwl/react:app ${appName} --routing --bundler=webpack --no-interactive` + ); + + runCLI(`build ${appName} --outputHashing none`); + + checkFilesExist( + `dist/apps/${appName}/index.html`, + `dist/apps/${appName}/runtime.js`, + `dist/apps/${appName}/polyfills.js`, + `dist/apps/${appName}/main.js` + ); + }, 250_000); + + it('should be able to add a redux slice', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + + runCLI(`g @nrwl/react:app ${appName} --bundler=webpack --no-interactive`); + runCLI(`g @nrwl/react:redux lemon --project=${appName}`); + runCLI(`g @nrwl/react:lib ${libName} --no-interactive`); + runCLI(`g @nrwl/react:redux orange --project=${libName}`); + + const appTestResults = await runCLIAsync(`test ${appName}`); + expect(appTestResults.combinedOutput).toContain( + 'Test Suites: 2 passed, 2 total' + ); + + const libTestResults = await runCLIAsync(`test ${libName}`); + expect(libTestResults.combinedOutput).toContain( + 'Test Suites: 2 passed, 2 total' + ); + }, 250_000); +}); diff --git a/e2e/react/src/react-package.test.ts b/e2e/react/src/react-package.test.ts index fd151baeb87ce..4eb24e21bd031 100644 --- a/e2e/react/src/react-package.test.ts +++ b/e2e/react/src/react-package.test.ts @@ -67,13 +67,13 @@ describe('Build React libraries and apps', () => { // generate buildable libs runCLI( - `generate @nrwl/react:library ${parentLib} --buildable --importPath=@${proj}/${parentLib} --no-interactive ` + `generate @nrwl/react:library ${parentLib} --bundler=rollup --importPath=@${proj}/${parentLib} --no-interactive ` ); runCLI( - `generate @nrwl/react:library ${childLib} --buildable --importPath=@${proj}/${childLib} --no-interactive ` + `generate @nrwl/react:library ${childLib} --bundler=rollup --importPath=@${proj}/${childLib} --no-interactive ` ); runCLI( - `generate @nrwl/react:library ${childLib2} --buildable --importPath=@${proj}/${childLib2} --no-interactive ` + `generate @nrwl/react:library ${childLib2} --bundler=rollup --importPath=@${proj}/${childLib2} --no-interactive ` ); createDep(parentLib, [childLib, childLib2]); @@ -237,7 +237,7 @@ export async function h() { return 'c'; } const libName = uniq('lib'); runCLI( - `generate @nrwl/react:lib ${libName} --buildable --importPath=@${proj}/${libName} --no-interactive` + `generate @nrwl/react:lib ${libName} --bundler=rollup --importPath=@${proj}/${libName} --no-interactive` ); const mainPath = `libs/${libName}/src/lib/${libName}.tsx`; @@ -261,10 +261,10 @@ describe('Build React applications and libraries with Vite', () => { }); it('should support bundling with Vite', async () => { - const libName = uniq('lib'); + const viteLib = uniq('vitelib'); runCLI( - `generate @nrwl/react:lib ${libName} --bundler=vite --no-interactive` + `generate @nrwl/react:lib ${viteLib} --bundler=vite --no-interactive` ); const packageJson = readJson('package.json'); @@ -272,13 +272,26 @@ describe('Build React applications and libraries with Vite', () => { expect(packageJson.dependencies['core-js']).toBeUndefined(); expect(packageJson.dependencies['tslib']).toBeUndefined(); - await runCLIAsync(`build ${libName}`); + await runCLIAsync(`build ${viteLib}`); checkFilesExist( - `dist/libs/${libName}/package.json`, - `dist/libs/${libName}/index.d.ts`, - `dist/libs/${libName}/index.js`, - `dist/libs/${libName}/index.mjs` + `dist/libs/${viteLib}/package.json`, + `dist/libs/${viteLib}/index.d.ts`, + `dist/libs/${viteLib}/index.js`, + `dist/libs/${viteLib}/index.mjs` ); - }); + + // Convert non-buildable lib to buildable one + const nonBuildableLib = uniq('nonbuildablelib'); + runCLI(`generate @nrwl/react:lib ${nonBuildableLib} --no-interactive`); + runCLI( + `generate @nrwl/vite:configuration ${nonBuildableLib} --uiFramework=react --no-interactive` + ); + await runCLIAsync(`build ${nonBuildableLib}`); + checkFilesExist( + `dist/libs/${nonBuildableLib}/index.d.ts`, + `dist/libs/${nonBuildableLib}/index.js`, + `dist/libs/${nonBuildableLib}/index.mjs` + ); + }, 300_000); }); diff --git a/e2e/react/src/react.test.ts b/e2e/react/src/react.test.ts index 60aa64d8ad1bf..3d0d4339390a2 100644 --- a/e2e/react/src/react.test.ts +++ b/e2e/react/src/react.test.ts @@ -74,34 +74,6 @@ describe('React Applications', () => { }); }, 500000); - it('should generate app with legacy-ie support', async () => { - const appName = uniq('app'); - - runCLI( - `generate @nrwl/react:app ${appName} --style=css --bundler=webpack --no-interactive` - ); - - // changing browser support of this application - updateFile(`apps/${appName}/.browserslistrc`, `IE 11`); - - await testGeneratedApp(appName, { - checkStyles: false, - checkLinter: false, - checkE2E: false, - }); - - const filesToCheck = [ - `dist/apps/${appName}/polyfills.es5.js`, - `dist/apps/${appName}/main.es5.js`, - ]; - - checkFilesExist(...filesToCheck); - - expect(readFile(`dist/apps/${appName}/index.html`)).toContain( - '' - ); - }, 250_000); - it('should be able to use JS and JSX', async () => { const appName = uniq('app'); const libName = uniq('lib'); @@ -222,47 +194,6 @@ describe('React Applications: --style option', () => { }); }); -describe('React Applications: additional packages', () => { - beforeAll(() => newProject()); - - it('should generate app with routing', async () => { - const appName = uniq('app'); - - runCLI( - `generate @nrwl/react:app ${appName} --routing --bundler=webpack --no-interactive` - ); - - runCLI(`build ${appName} --outputHashing none`); - - checkFilesExist( - `dist/apps/${appName}/index.html`, - `dist/apps/${appName}/runtime.js`, - `dist/apps/${appName}/polyfills.js`, - `dist/apps/${appName}/main.js` - ); - }, 250_000); - - it('should be able to add a redux slice', async () => { - const appName = uniq('app'); - const libName = uniq('lib'); - - runCLI(`g @nrwl/react:app ${appName} --bundler=webpack --no-interactive`); - runCLI(`g @nrwl/react:redux lemon --project=${appName}`); - runCLI(`g @nrwl/react:lib ${libName} --no-interactive`); - runCLI(`g @nrwl/react:redux orange --project=${libName}`); - - const appTestResults = await runCLIAsync(`test ${appName}`); - expect(appTestResults.combinedOutput).toContain( - 'Test Suites: 2 passed, 2 total' - ); - - const libTestResults = await runCLIAsync(`test ${libName}`); - expect(libTestResults.combinedOutput).toContain( - 'Test Suites: 2 passed, 2 total' - ); - }, 250_000); -}); - describe('React Applications and Libs with PostCSS', () => { let proj: string; diff --git a/packages/react/src/generators/library/lib/normalize-options.spec.ts b/packages/react/src/generators/library/lib/normalize-options.spec.ts index be9b4940b900d..62a2407c5a350 100644 --- a/packages/react/src/generators/library/lib/normalize-options.spec.ts +++ b/packages/react/src/generators/library/lib/normalize-options.spec.ts @@ -10,7 +10,7 @@ describe('normalizeOptions', () => { tree = createTreeWithEmptyWorkspace(); }); - it('should set unitTestRunner=jest and bundler=rollup by default', async () => { + it('should set unitTestRunner=jest and bundler=none by default', async () => { const options = normalizeOptions(tree, { name: 'test', style: 'css', @@ -19,12 +19,38 @@ describe('normalizeOptions', () => { expect(options).toMatchObject({ buildable: false, - bundler: 'rollup', + bundler: 'none', compiler: 'babel', unitTestRunner: 'jest', }); }); + it('should set buildable to true when bundler is not "none"', async () => { + let options = normalizeOptions(tree, { + name: 'test', + style: 'css', + linter: Linter.None, + bundler: 'rollup', + }); + + expect(options).toMatchObject({ + buildable: true, + bundler: 'rollup', + }); + + options = normalizeOptions(tree, { + name: 'test', + style: 'css', + linter: Linter.None, + bundler: 'vite', + }); + + expect(options).toMatchObject({ + buildable: true, + bundler: 'vite', + }); + }); + it('should set unitTestRunner=vitest by default when bundler is vite', async () => { const options = normalizeOptions(tree, { name: 'test', diff --git a/packages/react/src/generators/library/lib/normalize-options.ts b/packages/react/src/generators/library/lib/normalize-options.ts index ab518d9772d8d..bbcd12ac043fd 100644 --- a/packages/react/src/generators/library/lib/normalize-options.ts +++ b/packages/react/src/generators/library/lib/normalize-options.ts @@ -40,7 +40,7 @@ export function normalizeOptions( const normalized = { ...options, compiler: options.compiler ?? 'babel', - bundler: options.bundler ?? 'rollup', + bundler: options.bundler ?? 'none', fileName, routePath: `/${name}`, name: projectName, @@ -53,7 +53,7 @@ export function normalizeOptions( // Libraries with a bundler or is publishable must also be buildable. normalized.buildable = Boolean( - options.bundler || options.buildable || options.publishable + normalized.bundler !== 'none' || options.buildable || options.publishable ); normalized.unitTestRunner = diff --git a/packages/react/src/generators/library/library.spec.ts b/packages/react/src/generators/library/library.spec.ts index 1fe21bf25a706..2b6e8c5a0c9db 100644 --- a/packages/react/src/generators/library/library.spec.ts +++ b/packages/react/src/generators/library/library.spec.ts @@ -18,7 +18,7 @@ import { Schema } from './schema'; // which is v9 while we are testing for the new v10 version jest.mock('@nrwl/cypress/src/utils/cypress-version'); describe('lib', () => { - let appTree: Tree; + let tree: Tree; let mockedInstalledCypressVersion: jest.Mock< ReturnType > = installedCypressVersion as never; @@ -36,17 +36,17 @@ describe('lib', () => { beforeEach(() => { mockedInstalledCypressVersion.mockReturnValue(10); - appTree = createTreeWithEmptyV1Workspace(); + tree = createTreeWithEmptyV1Workspace(); }); describe('not nested', () => { - it('should update workspace.json', async () => { - await libraryGenerator(appTree, defaultSchema); - const workspaceJson = readJson(appTree, '/workspace.json'); - expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib'); - expect(workspaceJson.projects['my-lib'].architect.build).toBeUndefined(); - expect(workspaceJson.projects['my-lib'].architect.lint).toEqual({ - builder: '@nrwl/linter:eslint', + it('should update project configuration', async () => { + await libraryGenerator(tree, defaultSchema); + const project = readProjectConfiguration(tree, 'my-lib'); + expect(project.root).toEqual('libs/my-lib'); + expect(project.targets.build).toBeUndefined(); + expect(project.targets.lint).toEqual({ + executor: '@nrwl/linter:eslint', outputs: ['{options.outputFile}'], options: { lintFilePatterns: ['libs/my-lib/**/*.{ts,tsx,js,jsx}'], @@ -55,8 +55,8 @@ describe('lib', () => { }); it('should update tags', async () => { - await libraryGenerator(appTree, { ...defaultSchema, tags: 'one,two' }); - const project = readProjectConfiguration(appTree, 'my-lib'); + await libraryGenerator(tree, { ...defaultSchema, tags: 'one,two' }); + const project = readProjectConfiguration(tree, 'my-lib'); expect(project).toEqual( expect.objectContaining({ tags: ['one', 'two'], @@ -65,9 +65,9 @@ describe('lib', () => { }); it('should add react and react-dom packages to package.json if not already present', async () => { - await libraryGenerator(appTree, defaultSchema); + await libraryGenerator(tree, defaultSchema); - const packageJson = readJson(appTree, '/package.json'); + const packageJson = readJson(tree, '/package.json'); expect(packageJson).toMatchObject({ dependencies: { @@ -78,41 +78,41 @@ describe('lib', () => { }); it('should update root tsconfig.base.json', async () => { - await libraryGenerator(appTree, defaultSchema); - const tsconfigJson = readJson(appTree, '/tsconfig.base.json'); + await libraryGenerator(tree, defaultSchema); + const tsconfigJson = readJson(tree, '/tsconfig.base.json'); expect(tsconfigJson.compilerOptions.paths['@proj/my-lib']).toEqual([ 'libs/my-lib/src/index.ts', ]); }); it('should update root tsconfig.json when no tsconfig.base.json', async () => { - appTree.rename('tsconfig.base.json', 'tsconfig.json'); + tree.rename('tsconfig.base.json', 'tsconfig.json'); - await libraryGenerator(appTree, defaultSchema); + await libraryGenerator(tree, defaultSchema); - const tsconfigJson = readJson(appTree, '/tsconfig.json'); + const tsconfigJson = readJson(tree, '/tsconfig.json'); expect(tsconfigJson.compilerOptions.paths['@proj/my-lib']).toEqual([ 'libs/my-lib/src/index.ts', ]); }); it('should update root tsconfig.base.json (no existing path mappings)', async () => { - updateJson(appTree, 'tsconfig.base.json', (json) => { + updateJson(tree, 'tsconfig.base.json', (json) => { json.compilerOptions.paths = undefined; return json; }); - await libraryGenerator(appTree, defaultSchema); - const tsconfigJson = readJson(appTree, '/tsconfig.base.json'); + await libraryGenerator(tree, defaultSchema); + const tsconfigJson = readJson(tree, '/tsconfig.base.json'); expect(tsconfigJson.compilerOptions.paths['@proj/my-lib']).toEqual([ 'libs/my-lib/src/index.ts', ]); }); it('should create a local tsconfig.json', async () => { - await libraryGenerator(appTree, defaultSchema); + await libraryGenerator(tree, defaultSchema); - const tsconfigJson = readJson(appTree, 'libs/my-lib/tsconfig.json'); + const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.json'); expect(tsconfigJson.extends).toBe('../../tsconfig.base.json'); expect(tsconfigJson.references).toEqual([ { @@ -137,29 +137,29 @@ describe('lib', () => { }); it('should extend from root tsconfig.json when no tsconfig.base.json', async () => { - appTree.rename('tsconfig.base.json', 'tsconfig.json'); + tree.rename('tsconfig.base.json', 'tsconfig.json'); - await libraryGenerator(appTree, defaultSchema); + await libraryGenerator(tree, defaultSchema); - const tsconfigJson = readJson(appTree, 'libs/my-lib/tsconfig.json'); + const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.json'); expect(tsconfigJson.extends).toBe('../../tsconfig.json'); }); it('should extend the local tsconfig.json with tsconfig.spec.json', async () => { - await libraryGenerator(appTree, defaultSchema); - const tsconfigJson = readJson(appTree, 'libs/my-lib/tsconfig.spec.json'); + await libraryGenerator(tree, defaultSchema); + const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.spec.json'); expect(tsconfigJson.extends).toEqual('./tsconfig.json'); }); it('should extend the local tsconfig.json with tsconfig.lib.json', async () => { - await libraryGenerator(appTree, defaultSchema); - const tsconfigJson = readJson(appTree, 'libs/my-lib/tsconfig.lib.json'); + await libraryGenerator(tree, defaultSchema); + const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.lib.json'); expect(tsconfigJson.extends).toEqual('./tsconfig.json'); }); it('should ignore test files in tsconfig.lib.json', async () => { - await libraryGenerator(appTree, defaultSchema); - const tsconfigJson = readJson(appTree, 'libs/my-lib/tsconfig.lib.json'); + await libraryGenerator(tree, defaultSchema); + const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.lib.json'); expect(tsconfigJson.exclude).toEqual([ 'jest.config.ts', '**/*.spec.ts', @@ -174,19 +174,15 @@ describe('lib', () => { }); it('should generate files', async () => { - await libraryGenerator(appTree, defaultSchema); - expect(appTree.exists('libs/my-lib/package.json')).toBeFalsy(); - expect(appTree.exists(`libs/my-lib/jest.config.ts`)).toBeTruthy(); - expect(appTree.exists('libs/my-lib/src/index.ts')).toBeTruthy(); - expect(appTree.exists('libs/my-lib/src/lib/my-lib.tsx')).toBeTruthy(); - expect( - appTree.exists('libs/my-lib/src/lib/my-lib.module.css') - ).toBeTruthy(); - expect( - appTree.exists('libs/my-lib/src/lib/my-lib.spec.tsx') - ).toBeTruthy(); - - const eslintJson = readJson(appTree, 'libs/my-lib/.eslintrc.json'); + await libraryGenerator(tree, defaultSchema); + expect(tree.exists('libs/my-lib/package.json')).toBeFalsy(); + expect(tree.exists(`libs/my-lib/jest.config.ts`)).toBeTruthy(); + expect(tree.exists('libs/my-lib/src/index.ts')).toBeTruthy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.tsx')).toBeTruthy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.module.css')).toBeTruthy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.spec.tsx')).toBeTruthy(); + + const eslintJson = readJson(tree, 'libs/my-lib/.eslintrc.json'); expect(eslintJson).toMatchInlineSnapshot(` Object { "extends": Array [ @@ -225,12 +221,12 @@ describe('lib', () => { `); }); it('should update jest.config.ts for babel', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, buildable: true, compiler: 'babel', }); - expect(appTree.read('libs/my-lib/jest.config.ts', 'utf-8')).toContain( + expect(tree.read('libs/my-lib/jest.config.ts', 'utf-8')).toContain( "['babel-jest', { presets: ['@nrwl/react/babel'] }]" ); }); @@ -238,26 +234,26 @@ describe('lib', () => { describe('nested', () => { it('should update tags and implicitDependencies', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir', tags: 'one', }); - const myLib = readProjectConfiguration(appTree, 'my-dir-my-lib'); + const myLib = readProjectConfiguration(tree, 'my-dir-my-lib'); expect(myLib).toEqual( expect.objectContaining({ tags: ['one'], }) ); - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, name: 'myLib2', directory: 'myDir', tags: 'one,two', }); - const myLib2 = readProjectConfiguration(appTree, 'my-dir-my-lib2'); + const myLib2 = readProjectConfiguration(tree, 'my-dir-my-lib2'); expect(myLib2).toEqual( expect.objectContaining({ tags: ['one', 'two'], @@ -266,34 +262,34 @@ describe('lib', () => { }); it('should generate files', async () => { - await libraryGenerator(appTree, { ...defaultSchema, directory: 'myDir' }); - expect(appTree.exists(`libs/my-dir/my-lib/jest.config.ts`)).toBeTruthy(); - expect(appTree.exists('libs/my-dir/my-lib/src/index.ts')).toBeTruthy(); + await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); + expect(tree.exists(`libs/my-dir/my-lib/jest.config.ts`)).toBeTruthy(); + expect(tree.exists('libs/my-dir/my-lib/src/index.ts')).toBeTruthy(); expect( - appTree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.tsx') + tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.tsx') ).toBeTruthy(); expect( - appTree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.module.css') + tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.module.css') ).toBeTruthy(); expect( - appTree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.spec.tsx') + tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.spec.tsx') ).toBeTruthy(); }); it('should update jest.config.ts for babel', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir', buildable: true, compiler: 'babel', }); - expect( - appTree.read('libs/my-dir/my-lib/jest.config.ts', 'utf-8') - ).toContain("['babel-jest', { presets: ['@nrwl/react/babel'] }]"); + expect(tree.read('libs/my-dir/my-lib/jest.config.ts', 'utf-8')).toContain( + "['babel-jest', { presets: ['@nrwl/react/babel'] }]" + ); }); it('should update workspace.json', async () => { - await libraryGenerator(appTree, { ...defaultSchema, directory: 'myDir' }); - const workspaceJson = readJson(appTree, '/workspace.json'); + await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); + const workspaceJson = readJson(tree, '/workspace.json'); expect(workspaceJson.projects['my-dir-my-lib'].root).toEqual( 'libs/my-dir/my-lib' @@ -308,8 +304,8 @@ describe('lib', () => { }); it('should update root tsconfig.base.json', async () => { - await libraryGenerator(appTree, { ...defaultSchema, directory: 'myDir' }); - const tsconfigJson = readJson(appTree, '/tsconfig.base.json'); + await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); + const tsconfigJson = readJson(tree, '/tsconfig.base.json'); expect(tsconfigJson.compilerOptions.paths['@proj/my-dir/my-lib']).toEqual( ['libs/my-dir/my-lib/src/index.ts'] ); @@ -319,11 +315,11 @@ describe('lib', () => { }); it('should update root tsconfig.json when no tsconfig.base.json', async () => { - appTree.rename('tsconfig.base.json', 'tsconfig.json'); + tree.rename('tsconfig.base.json', 'tsconfig.json'); - await libraryGenerator(appTree, { ...defaultSchema, directory: 'myDir' }); + await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); - const tsconfigJson = readJson(appTree, '/tsconfig.json'); + const tsconfigJson = readJson(tree, '/tsconfig.json'); expect(tsconfigJson.compilerOptions.paths['@proj/my-dir/my-lib']).toEqual( ['libs/my-dir/my-lib/src/index.ts'] ); @@ -333,12 +329,9 @@ describe('lib', () => { }); it('should create a local tsconfig.json', async () => { - await libraryGenerator(appTree, { ...defaultSchema, directory: 'myDir' }); + await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); - const tsconfigJson = readJson( - appTree, - 'libs/my-dir/my-lib/tsconfig.json' - ); + const tsconfigJson = readJson(tree, 'libs/my-dir/my-lib/tsconfig.json'); expect(tsconfigJson.extends).toBe('../../../tsconfig.base.json'); expect(tsconfigJson.references).toEqual([ { @@ -351,50 +344,39 @@ describe('lib', () => { }); it('should extend from root tsconfig.json when no tsconfig.base.json', async () => { - appTree.rename('tsconfig.base.json', 'tsconfig.json'); + tree.rename('tsconfig.base.json', 'tsconfig.json'); - await libraryGenerator(appTree, { ...defaultSchema, directory: 'myDir' }); + await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); - const tsconfigJson = readJson( - appTree, - 'libs/my-dir/my-lib/tsconfig.json' - ); + const tsconfigJson = readJson(tree, 'libs/my-dir/my-lib/tsconfig.json'); expect(tsconfigJson.extends).toBe('../../../tsconfig.json'); }); }); describe('--style scss', () => { it('should use scss for styles', async () => { - await libraryGenerator(appTree, { ...defaultSchema, style: 'scss' }); + await libraryGenerator(tree, { ...defaultSchema, style: 'scss' }); expect( - appTree.exists('libs/my-lib/src/lib/my-lib.module.scss') + tree.exists('libs/my-lib/src/lib/my-lib.module.scss') ).toBeTruthy(); }); }); describe('--style none', () => { it('should not use styles when style none', async () => { - await libraryGenerator(appTree, { ...defaultSchema, style: 'none' }); - - expect(appTree.exists('libs/my-lib/src/lib/my-lib.tsx')).toBeTruthy(); - expect( - appTree.exists('libs/my-lib/src/lib/my-lib.spec.tsx') - ).toBeTruthy(); - expect(appTree.exists('libs/my-lib/src/lib/my-lib.css')).toBeFalsy(); - expect(appTree.exists('libs/my-lib/src/lib/my-lib.scss')).toBeFalsy(); - expect(appTree.exists('libs/my-lib/src/lib/my-lib.styl')).toBeFalsy(); - expect( - appTree.exists('libs/my-lib/src/lib/my-lib.module.css') - ).toBeFalsy(); - expect( - appTree.exists('libs/my-lib/src/lib/my-lib.module.scss') - ).toBeFalsy(); - expect( - appTree.exists('libs/my-lib/src/lib/my-lib.module.styl') - ).toBeFalsy(); - - const content = appTree.read('libs/my-lib/src/lib/my-lib.tsx', 'utf-8'); + await libraryGenerator(tree, { ...defaultSchema, style: 'none' }); + + expect(tree.exists('libs/my-lib/src/lib/my-lib.tsx')).toBeTruthy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.spec.tsx')).toBeTruthy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.css')).toBeFalsy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.scss')).toBeFalsy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.styl')).toBeFalsy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.module.css')).toBeFalsy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.module.scss')).toBeFalsy(); + expect(tree.exists('libs/my-lib/src/lib/my-lib.module.styl')).toBeFalsy(); + + const content = tree.read('libs/my-lib/src/lib/my-lib.tsx', 'utf-8'); expect(content).not.toContain('styled-components'); expect(content).not.toContain(''); expect(content).not.toContain('@emotion/styled'); @@ -412,22 +394,22 @@ describe('lib', () => { describe('--no-component', () => { it('should not generate components or styles', async () => { - await libraryGenerator(appTree, { ...defaultSchema, component: false }); + await libraryGenerator(tree, { ...defaultSchema, component: false }); - expect(appTree.exists('libs/my-lib/src/lib')).toBeFalsy(); + expect(tree.exists('libs/my-lib/src/lib')).toBeFalsy(); }); }); describe('--unit-test-runner none', () => { it('should not generate test configuration', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, unitTestRunner: 'none', }); - expect(appTree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy(); - expect(appTree.exists('libs/my-lib/jest.config.ts')).toBeFalsy(); - const workspaceJson = readJson(appTree, 'workspace.json'); + expect(tree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy(); + expect(tree.exists('libs/my-lib/jest.config.ts')).toBeFalsy(); + const workspaceJson = readJson(tree, 'workspace.json'); expect(workspaceJson.projects['my-lib'].architect.test).toBeUndefined(); expect(workspaceJson.projects['my-lib'].architect.lint) .toMatchInlineSnapshot(` @@ -448,7 +430,7 @@ describe('lib', () => { describe('--appProject', () => { it('should add new route to existing routing code', async () => { - await applicationGenerator(appTree, { + await applicationGenerator(tree, { compiler: 'babel', e2eTestRunner: 'none', linter: Linter.EsLint, @@ -461,13 +443,13 @@ describe('lib', () => { bundler: 'webpack', }); - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, appProject: 'my-app', }); - const appSource = appTree.read('apps/my-app/src/app/app.tsx', 'utf-8'); - const mainSource = appTree.read('apps/my-app/src/main.tsx', 'utf-8'); + const appSource = tree.read('apps/my-app/src/app/app.tsx', 'utf-8'); + const mainSource = tree.read('apps/my-app/src/main.tsx', 'utf-8'); expect(mainSource).toContain('react-router-dom'); expect(mainSource).toContain(''); @@ -477,7 +459,7 @@ describe('lib', () => { }); it('should initialize routes if none were set up then add new route', async () => { - await applicationGenerator(appTree, { + await applicationGenerator(tree, { e2eTestRunner: 'none', linter: Linter.EsLint, skipFormat: true, @@ -488,13 +470,13 @@ describe('lib', () => { bundler: 'webpack', }); - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, appProject: 'my-app', }); - const appSource = appTree.read('apps/my-app/src/app/app.tsx', 'utf-8'); - const mainSource = appTree.read('apps/my-app/src/main.tsx', 'utf-8'); + const appSource = tree.read('apps/my-app/src/app/app.tsx', 'utf-8'); + const mainSource = tree.read('apps/my-app/src/main.tsx', 'utf-8'); expect(mainSource).toContain('react-router-dom'); expect(mainSource).toContain(''); @@ -506,12 +488,12 @@ describe('lib', () => { describe('--buildable', () => { it('should have a builder defined', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, buildable: true, }); - const workspaceJson = getProjects(appTree); + const workspaceJson = getProjects(tree); expect(workspaceJson.get('my-lib').targets.build).toBeDefined(); }); @@ -519,13 +501,13 @@ describe('lib', () => { describe('--publishable', () => { it('should add build architect', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, publishable: true, importPath: '@proj/my-lib', }); - const workspaceJson = getProjects(appTree); + const workspaceJson = getProjects(tree); expect(workspaceJson.get('my-lib').targets.build).toMatchObject({ executor: '@nrwl/web:rollup', @@ -545,7 +527,7 @@ describe('lib', () => { expect.assertions(1); try { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir', publishable: true, @@ -558,15 +540,15 @@ describe('lib', () => { }); it('should support styled-components', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, publishable: true, importPath: '@proj/my-lib', style: 'styled-components', }); - const workspaceJson = readJson(appTree, '/workspace.json'); - const babelrc = readJson(appTree, 'libs/my-lib/.babelrc'); + const workspaceJson = readJson(tree, '/workspace.json'); + const babelrc = readJson(tree, 'libs/my-lib/.babelrc'); expect(workspaceJson.projects['my-lib'].architect.build).toMatchObject({ options: { @@ -579,16 +561,16 @@ describe('lib', () => { }); it('should support @emotion/styled', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, publishable: true, importPath: '@proj/my-lib', style: '@emotion/styled', }); - const workspaceJson = readJson(appTree, '/workspace.json'); - const babelrc = readJson(appTree, 'libs/my-lib/.babelrc'); - const tsconfigJson = readJson(appTree, 'libs/my-lib/tsconfig.json'); + const workspaceJson = readJson(tree, '/workspace.json'); + const babelrc = readJson(tree, 'libs/my-lib/.babelrc'); + const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.json'); expect(workspaceJson.projects['my-lib'].architect.build).toMatchObject({ options: { @@ -602,15 +584,15 @@ describe('lib', () => { }); it('should support styled-jsx', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, publishable: true, importPath: '@proj/my-lib', style: 'styled-jsx', }); - const workspaceJson = readJson(appTree, '/workspace.json'); - const babelrc = readJson(appTree, 'libs/my-lib/.babelrc'); + const workspaceJson = readJson(tree, '/workspace.json'); + const babelrc = readJson(tree, 'libs/my-lib/.babelrc'); expect(workspaceJson.projects['my-lib'].architect.build).toMatchObject({ options: { @@ -621,14 +603,14 @@ describe('lib', () => { }); it('should support style none', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, publishable: true, importPath: '@proj/my-lib', style: 'none', }); - const workspaceJson = readJson(appTree, '/workspace.json'); + const workspaceJson = readJson(tree, '/workspace.json'); expect(workspaceJson.projects['my-lib'].architect.build).toMatchObject({ options: { @@ -638,39 +620,39 @@ describe('lib', () => { }); it('should add package.json and .babelrc', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, publishable: true, importPath: '@proj/my-lib', }); - const packageJson = readJson(appTree, '/libs/my-lib/package.json'); + const packageJson = readJson(tree, '/libs/my-lib/package.json'); expect(packageJson.name).toEqual('@proj/my-lib'); - expect(appTree.exists('/libs/my-lib/.babelrc')); + expect(tree.exists('/libs/my-lib/.babelrc')); }); }); describe('--js', () => { it('should generate JS files', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, js: true, }); - expect(appTree.exists('/libs/my-lib/src/index.js')).toBe(true); + expect(tree.exists('/libs/my-lib/src/index.js')).toBe(true); }); }); describe('--importPath', () => { it('should update the package.json & tsconfig with the given import path', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, publishable: true, directory: 'myDir', importPath: '@myorg/lib', }); - const packageJson = readJson(appTree, 'libs/my-dir/my-lib/package.json'); - const tsconfigJson = readJson(appTree, '/tsconfig.base.json'); + const packageJson = readJson(tree, 'libs/my-dir/my-lib/package.json'); + const tsconfigJson = readJson(tree, '/tsconfig.base.json'); expect(packageJson.name).toBe('@myorg/lib'); expect( @@ -679,7 +661,7 @@ describe('lib', () => { }); it('should fail if the same importPath has already been used', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, name: 'myLib1', publishable: true, @@ -687,7 +669,7 @@ describe('lib', () => { }); try { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, name: 'myLib2', publishable: true, @@ -705,11 +687,11 @@ describe('lib', () => { describe('--no-strict', () => { it('should not add options for strict mode', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, strict: false, }); - const tsconfigJson = readJson(appTree, '/libs/my-lib/tsconfig.json'); + const tsconfigJson = readJson(tree, '/libs/my-lib/tsconfig.json'); expect( tsconfigJson.compilerOptions.forceConsistentCasingInFileNames @@ -728,12 +710,12 @@ describe('lib', () => { describe('--compiler', () => { it('should install swc dependencies if needed', async () => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, buildable: true, compiler: 'swc', }); - const packageJson = readJson(appTree, 'package.json'); + const packageJson = readJson(tree, 'package.json'); expect(packageJson.devDependencies['@swc/core']).toEqual( expect.any(String) @@ -767,7 +749,7 @@ describe('lib', () => { `( 'should generate valid .babelrc JSON config for CSS-in-JS solutions', async ({ style }) => { - await libraryGenerator(appTree, { + await libraryGenerator(tree, { ...defaultSchema, style, compiler: 'babel', @@ -775,7 +757,7 @@ describe('lib', () => { }); expect(() => { - readJson(appTree, `libs/my-lib/.babelrc`); + readJson(tree, `libs/my-lib/.babelrc`); }).not.toThrow(); } ); diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index d6303a242ee1c..3dc1dad08091c 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -6,11 +6,9 @@ import { formatFiles, generateFiles, GeneratorCallback, - getProjects, getWorkspaceLayout, joinPathFragments, names, - normalizePath, offsetFromRoot, toJS, Tree, @@ -26,7 +24,6 @@ import { getRootTsConfigPathInTree, } from '@nrwl/workspace/src/utilities/typescript'; import * as ts from 'typescript'; -import { assertValidStyle } from '../../utils/assertion'; import { addBrowserRouter, addInitialRoutes, diff --git a/packages/react/src/generators/library/schema.d.ts b/packages/react/src/generators/library/schema.d.ts index 71a09562202c6..c6062ec2e6c0e 100644 --- a/packages/react/src/generators/library/schema.d.ts +++ b/packages/react/src/generators/library/schema.d.ts @@ -4,7 +4,7 @@ import { SupportedStyles } from '../../../typings/style'; export interface Schema { appProject?: string; buildable?: boolean; - bundler?: 'rollup' | 'vite'; + bundler?: 'none' | 'rollup' | 'vite'; compiler?: 'babel' | 'swc'; component?: boolean; directory?: string; diff --git a/packages/react/src/generators/library/schema.json b/packages/react/src/generators/library/schema.json index eca107736ffc2..2b9cd839bc833 100644 --- a/packages/react/src/generators/library/schema.json +++ b/packages/react/src/generators/library/schema.json @@ -162,9 +162,9 @@ }, "bundler": { "type": "string", - "description": "The bundler to use.", - "enum": ["vite", "rollup"], - "x-prompt": "Which bundler would you like to use to build the library?" + "description": "The bundler to use. Choosing 'none' means this library is not buildable.", + "enum": ["none", "vite", "rollup"], + "x-prompt": "Which bundler would you like to use to build the library? Choose 'none' to skip build setup." }, "compiler": { "type": "string", diff --git a/packages/react/src/generators/storybook-configuration/configuration.ts b/packages/react/src/generators/storybook-configuration/configuration.ts index d978cecaa0bb5..35d9fb77e20f4 100644 --- a/packages/react/src/generators/storybook-configuration/configuration.ts +++ b/packages/react/src/generators/storybook-configuration/configuration.ts @@ -30,7 +30,7 @@ export async function storybookConfigurationGenerator( host: Tree, schema: StorybookConfigureSchema ) { - let bundler = schema.bundler; + let bundler = schema.bundler ?? 'webpack'; const projectConfig = readProjectConfiguration(host, schema.name); if ( diff --git a/packages/react/src/generators/storybook-configuration/schema.json b/packages/react/src/generators/storybook-configuration/schema.json index d30759ae28017..a99a03b88e899 100644 --- a/packages/react/src/generators/storybook-configuration/schema.json +++ b/packages/react/src/generators/storybook-configuration/schema.json @@ -80,9 +80,7 @@ }, "bundler": { "description": "The Storybook builder to use.", - "enum": ["vite", "webpack"], - "x-prompt": "Which Storybook builder do you want to use?", - "default": "webpack" + "enum": ["vite", "webpack"] } }, "required": ["name"], diff --git a/packages/vite/src/generators/configuration/configuration.ts b/packages/vite/src/generators/configuration/configuration.ts index 49fde955a85cf..6db0289c6f2c8 100644 --- a/packages/vite/src/generators/configuration/configuration.ts +++ b/packages/vite/src/generators/configuration/configuration.ts @@ -22,14 +22,21 @@ import { Schema } from './schema'; export async function viteConfigurationGenerator(tree: Tree, schema: Schema) { const tasks: GeneratorCallback[] = []; - const { targets } = readProjectConfiguration(tree, schema.project); + const { targets, projectType } = readProjectConfiguration( + tree, + schema.project + ); let buildTarget = 'build'; let serveTarget = 'serve'; + schema.includeLib ??= projectType === 'library'; + if (!schema.newProject) { buildTarget = findExistingTargets(targets).buildTarget; serveTarget = findExistingTargets(targets).serveTarget; - moveAndEditIndexHtml(tree, schema, buildTarget); + if (projectType === 'application') { + moveAndEditIndexHtml(tree, schema, buildTarget); + } editTsConfig(tree, schema); } diff --git a/packages/vite/src/generators/configuration/schema.json b/packages/vite/src/generators/configuration/schema.json index 8281bc2ddcfda..29614c003e564 100644 --- a/packages/vite/src/generators/configuration/schema.json +++ b/packages/vite/src/generators/configuration/schema.json @@ -19,8 +19,7 @@ "includeLib": { "type": "boolean", "description": "Add a library build option and skip the server option.", - "default": false, - "x-prompt": "Does this project contain a buildable library?" + "hidden": true }, "uiFramework": { "type": "string",