feat(react): remove unnecessary dependencies from @nrwl/react (#13525)
This commit is contained in:
parent
4c723de444
commit
cded83b2c5
@ -147,6 +147,7 @@ It only uses language primitives and immutable objects
|
||||
- [defaultTasksRunner](../../devkit/index#defaulttasksrunner)
|
||||
- [detectPackageManager](../../devkit/index#detectpackagemanager)
|
||||
- [detectWorkspaceScope](../../devkit/index#detectworkspacescope)
|
||||
- [ensurePackage](../../devkit/index#ensurepackage)
|
||||
- [extractLayoutDirectory](../../devkit/index#extractlayoutdirectory)
|
||||
- [formatFiles](../../devkit/index#formatfiles)
|
||||
- [generateFiles](../../devkit/index#generatefiles)
|
||||
@ -1164,6 +1165,39 @@ Detect workspace scope from the package.json name
|
||||
|
||||
---
|
||||
|
||||
### ensurePackage
|
||||
|
||||
▸ **ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `Promise`<`void`\>
|
||||
|
||||
Ensure that dependencies and devDependencies from package.json are installed at the required versions.
|
||||
|
||||
For example:
|
||||
|
||||
```typescript
|
||||
ensureDependencies(tree, {}, { '@nrwl/jest': nxVersion });
|
||||
```
|
||||
|
||||
This will check that @nrwl/jest@<nxVersion> exists in devDependencies.
|
||||
If it exists then function returns, otherwise it will install the package before continuing.
|
||||
When running with --dryRun, the function will throw when dependencies are missing.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------------------------ | :-------------------------------- | :------------------------------------- |
|
||||
| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |
|
||||
| `pkg` | `string` | the package to check (e.g. @nrwl/jest) |
|
||||
| `requiredVersion` | `string` | the version to check |
|
||||
| `options` | `Object` | |
|
||||
| `options.dev?` | `boolean` | - |
|
||||
| `options.throwOnMissing?` | `boolean` | - |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Promise`<`void`\>
|
||||
|
||||
---
|
||||
|
||||
### extractLayoutDirectory
|
||||
|
||||
▸ **extractLayoutDirectory**(`directory`): `Object`
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -18,6 +18,12 @@
|
||||
"description": "Init Webpack Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uiFramework": {
|
||||
"type": "string",
|
||||
"description": "UI Framework to use for Vite.",
|
||||
"enum": ["react", "none"],
|
||||
"x-prompt": "What UI framework plugin should Webpack use?"
|
||||
},
|
||||
"compiler": {
|
||||
"type": "string",
|
||||
"enum": ["babel", "swc", "tsc"],
|
||||
|
||||
@ -225,6 +225,7 @@ export { readJsonFile, writeJsonFile } from 'nx/src/utils/fileutils';
|
||||
*/
|
||||
export {
|
||||
addDependenciesToPackageJson,
|
||||
ensurePackage,
|
||||
removeDependenciesFromPackageJson,
|
||||
} from './src/utils/package-json';
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export async function* combineAsyncIterableIterators(
|
||||
...iterators: { 0: AsyncIterableIterator<any> } & AsyncIterableIterator<any>[]
|
||||
) {
|
||||
export async function* combineAsyncIterableIterators<T = any>(
|
||||
...iterators: { 0: AsyncIterableIterator<T> } & AsyncIterableIterator<T>[]
|
||||
): AsyncGenerator<T> {
|
||||
let [options] = iterators;
|
||||
if (typeof options.next === 'function') {
|
||||
options = Object.create(null);
|
||||
4
packages/devkit/src/utils/async-iterable/index.ts
Normal file
4
packages/devkit/src/utils/async-iterable/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './create-async-iterable';
|
||||
export * from './combine-async-iteratable-iterators';
|
||||
export * from './map-async-iteratable';
|
||||
export * from './tap-async-iteratable';
|
||||
@ -5,7 +5,7 @@ export async function* mapAsyncIterable<T = any, I = any, O = any>(
|
||||
index?: number,
|
||||
data?: AsyncIterable<T> | AsyncIterableIterator<T>
|
||||
) => O
|
||||
) {
|
||||
): AsyncIterable<O> | AsyncIterableIterator<O> {
|
||||
async function* f() {
|
||||
const generator = data[Symbol.asyncIterator] || data[Symbol.iterator];
|
||||
const iterator = generator.call(data);
|
||||
@ -1,4 +1,4 @@
|
||||
import { tapAsyncIterator } from './tap-async-iteratable';
|
||||
import { tapAsyncIterable } from './tap-async-iteratable';
|
||||
|
||||
describe('tapAsyncIterator', () => {
|
||||
it('should tap values', async () => {
|
||||
@ -11,7 +11,7 @@ describe('tapAsyncIterator', () => {
|
||||
const tapped = [];
|
||||
const results = [];
|
||||
|
||||
const c = tapAsyncIterator(f(), (x) => {
|
||||
const c = tapAsyncIterable(f(), (x) => {
|
||||
tapped.push(`tap: ${x}`);
|
||||
});
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { mapAsyncIterable } from './map-async-iteratable';
|
||||
|
||||
export async function* tapAsyncIterator<T = any, I = any, O = any>(
|
||||
export async function* tapAsyncIterable<T = any, I = any, O = any>(
|
||||
data: AsyncIterable<T> | AsyncIterableIterator<T>,
|
||||
fn: (input: I) => void
|
||||
) {
|
||||
): AsyncIterable<T> | AsyncIterableIterator<T> {
|
||||
return yield* mapAsyncIterable(data, (x) => {
|
||||
fn(x);
|
||||
return x;
|
||||
@ -1,6 +1,6 @@
|
||||
import type { Tree } from 'nx/src/generators/tree';
|
||||
import { readJson, writeJson } from 'nx/src/generators/utils/json';
|
||||
import { addDependenciesToPackageJson } from './package-json';
|
||||
import { addDependenciesToPackageJson, ensurePackage } from './package-json';
|
||||
import { createTree } from 'nx/src/generators/testing-utils/create-tree';
|
||||
|
||||
describe('addDependenciesToPackageJson', () => {
|
||||
@ -310,3 +310,42 @@ describe('addDependenciesToPackageJson', () => {
|
||||
expect(installTask).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ensureDependencies', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTree();
|
||||
});
|
||||
|
||||
it('should return without error when dependency is satisfied', async () => {
|
||||
writeJson(tree, 'package.json', {
|
||||
devDependencies: {
|
||||
'@nrwl/vite': '15.0.0',
|
||||
},
|
||||
});
|
||||
|
||||
await expect(
|
||||
ensurePackage(tree, '@nrwl/vite', '>=15.0.0', {
|
||||
throwOnMissing: true,
|
||||
})
|
||||
).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('should throw when dependencies are missing', async () => {
|
||||
writeJson(tree, 'package.json', {});
|
||||
|
||||
await expect(() =>
|
||||
ensurePackage(tree, '@nrwl/does-not-exist', '>=15.0.0', {
|
||||
throwOnMissing: true,
|
||||
})
|
||||
).rejects.toThrow(/-D( -W)? @nrwl\/does-not-exist@>=15.0.0/);
|
||||
|
||||
await expect(() =>
|
||||
ensurePackage(tree, '@nrwl/does-not-exist', '>=15.0.0', {
|
||||
dev: false,
|
||||
throwOnMissing: true,
|
||||
})
|
||||
).rejects.toThrow('@nrwl/does-not-exist@>=15.0.0');
|
||||
});
|
||||
});
|
||||
|
||||
@ -2,7 +2,9 @@ import { readJson, updateJson } from 'nx/src/generators/utils/json';
|
||||
import { installPackagesTask } from '../tasks/install-packages-task';
|
||||
import type { Tree } from 'nx/src/generators/tree';
|
||||
import { GeneratorCallback } from 'nx/src/config/misc-interfaces';
|
||||
import { coerce, gt } from 'semver';
|
||||
import { coerce, gt, satisfies } from 'semver';
|
||||
import { getPackageManagerCommand } from 'nx/src/utils/package-manager';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
const NON_SEMVER_TAGS = {
|
||||
'*': 2,
|
||||
@ -274,3 +276,73 @@ function requiresRemovingOfPackages(
|
||||
|
||||
return needsDepsUpdate || needsDevDepsUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef EnsurePackageOptions
|
||||
* @type {object}
|
||||
* @property {boolean} dev indicate if the package is a dev dependency
|
||||
* @property {throwOnMissing} boolean throws an error when the packag is missing
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ensure that dependencies and devDependencies from package.json are installed at the required versions.
|
||||
*
|
||||
* For example:
|
||||
* ```typescript
|
||||
* ensureDependencies(tree, {}, { '@nrwl/jest': nxVersion })
|
||||
* ```
|
||||
* This will check that @nrwl/jest@<nxVersion> exists in devDependencies.
|
||||
* If it exists then function returns, otherwise it will install the package before continuing.
|
||||
* When running with --dryRun, the function will throw when dependencies are missing.
|
||||
*
|
||||
* @param tree the file system tree
|
||||
* @param pkg the package to check (e.g. @nrwl/jest)
|
||||
* @param requiredVersion the version to check
|
||||
* @param {EnsurePackageOptions} options
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function ensurePackage(
|
||||
tree: Tree,
|
||||
pkg: string,
|
||||
requiredVersion: string,
|
||||
options: {
|
||||
dev?: boolean;
|
||||
throwOnMissing?: boolean;
|
||||
} = {}
|
||||
): Promise<void> {
|
||||
let version: string;
|
||||
|
||||
// Read package and version from root package.json file.
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
const dev = options.dev ?? true;
|
||||
const throwOnMissing = options.throwOnMissing ?? !!process.env.NX_DRY_RUN; // NX_DRY_RUN is set in `packages/nx/src/command-line/generate.ts`
|
||||
const pmc = getPackageManagerCommand();
|
||||
const field = dev ? 'devDependencies' : 'dependencies';
|
||||
|
||||
version = packageJson[field]?.[pkg];
|
||||
|
||||
// If package not found, try to resolve it using Node and get its version.
|
||||
if (!version) {
|
||||
try {
|
||||
version = require(`${pkg}/package.json`).version;
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (!satisfies(version, requiredVersion)) {
|
||||
const installCmd = `${
|
||||
dev ? pmc.addDev : pmc.add
|
||||
} ${pkg}@${requiredVersion}`;
|
||||
if (throwOnMissing) {
|
||||
throw new Error(
|
||||
`Required package ${pkg}@${requiredVersion} is missing. Run "${installCmd}", and then try again.`
|
||||
);
|
||||
} else {
|
||||
execSync(installCmd, {
|
||||
cwd: tree.root,
|
||||
stdio: [0, 1, 2],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import { normalizeOptions } from './lib/normalize';
|
||||
|
||||
import { EsBuildExecutorOptions } from './schema';
|
||||
import { removeSync, writeJsonSync } from 'fs-extra';
|
||||
import { createAsyncIterable } from '@nrwl/js/src/utils/async-iterable/create-async-iterable';
|
||||
import { createAsyncIterable } from '@nrwl/devkit/src/utils/async-iterable';
|
||||
import { buildEsbuildOptions } from './lib/build-esbuild-options';
|
||||
import { getExtraDependencies } from './lib/get-extra-dependencies';
|
||||
import { DependentBuildableProjectNode } from '@nrwl/workspace/src/utilities/buildable-libs-utils';
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
"builders": "./executors.json",
|
||||
"dependencies": {
|
||||
"@nrwl/devkit": "file:../devkit",
|
||||
"@nrwl/jest": "file:../jest",
|
||||
"@nrwl/linter": "file:../linter",
|
||||
"@nrwl/workspace": "file:../workspace",
|
||||
"chalk": "4.1.0",
|
||||
|
||||
@ -2,6 +2,7 @@ import {
|
||||
addDependenciesToPackageJson,
|
||||
addProjectConfiguration,
|
||||
convertNxGenerator,
|
||||
ensurePackage,
|
||||
extractLayoutDirectory,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
@ -18,7 +19,6 @@ import {
|
||||
writeJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { getImportPath } from 'nx/src/utils/path';
|
||||
import { jestProjectGenerator } from '@nrwl/jest';
|
||||
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||
import {
|
||||
@ -293,6 +293,8 @@ async function addJest(
|
||||
tree: Tree,
|
||||
options: NormalizedSchema
|
||||
): Promise<GeneratorCallback> {
|
||||
await ensurePackage(tree, '@nrwl/jest', nxVersion);
|
||||
const { jestProjectGenerator } = await import('@nrwl/jest');
|
||||
return await jestProjectGenerator(tree, {
|
||||
...options,
|
||||
project: options.name,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { cacheDir, ExecutorContext, logger } from '@nrwl/devkit';
|
||||
import { exec, execSync } from 'child_process';
|
||||
import { removeSync } from 'fs-extra';
|
||||
import { createAsyncIterable } from '../async-iterable/create-async-iterable';
|
||||
import { createAsyncIterable } from '@nrwl/devkit/src/utils/async-iterable';
|
||||
import { NormalizedSwcExecutorOptions, SwcCliOptions } from '../schema';
|
||||
import { printDiagnostics } from '../typescript/print-diagnostics';
|
||||
import { runTypeCheck, TypeCheckOptions } from '../typescript/run-type-check';
|
||||
|
||||
@ -4,7 +4,7 @@ import {
|
||||
TypeScriptCompilationOptions,
|
||||
} from '@nrwl/workspace/src/utilities/typescript/compilation';
|
||||
import type { Diagnostic } from 'typescript';
|
||||
import { createAsyncIterable } from '../async-iterable/create-async-iterable';
|
||||
import { createAsyncIterable } from '@nrwl/devkit/src/utils/async-iterable';
|
||||
import { NormalizedExecutorOptions } from '../schema';
|
||||
|
||||
const TYPESCRIPT_FOUND_N_ERRORS_WATCHING_FOR_FILE_CHANGES = 6194;
|
||||
|
||||
@ -34,7 +34,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nrwl/devkit": "file:../devkit",
|
||||
"@nrwl/jest": "file:../jest",
|
||||
"@phenomnomnominal/tsquery": "4.1.1",
|
||||
"nx": "file:../nx",
|
||||
"tmp": "~0.2.1",
|
||||
|
||||
@ -2,6 +2,7 @@ import {
|
||||
addDependenciesToPackageJson,
|
||||
addProjectConfiguration,
|
||||
convertNxGenerator,
|
||||
ensurePackage,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
joinPathFragments,
|
||||
@ -11,17 +12,22 @@ import {
|
||||
Tree,
|
||||
updateWorkspaceConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
import { addPropertyToJestConfig, jestProjectGenerator } from '@nrwl/jest';
|
||||
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
||||
import { join } from 'path';
|
||||
import { workspaceLintPluginDir } from '../../utils/workspace-lint-rules';
|
||||
import { swcCoreVersion, swcNodeVersion } from 'nx/src/utils/versions';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
|
||||
export const WORKSPACE_RULES_PROJECT_NAME = 'eslint-rules';
|
||||
|
||||
export const WORKSPACE_PLUGIN_DIR = 'tools/eslint-rules';
|
||||
|
||||
export async function lintWorkspaceRulesProjectGenerator(tree: Tree) {
|
||||
await ensurePackage(tree, '@nrwl/jest/', nxVersion);
|
||||
const { addPropertyToJestConfig, jestProjectGenerator } = await import(
|
||||
'@nrwl/jest'
|
||||
);
|
||||
|
||||
// Noop if the workspace rules project already exists
|
||||
try {
|
||||
readProjectConfiguration(tree, WORKSPACE_RULES_PROJECT_NAME);
|
||||
|
||||
@ -4,11 +4,11 @@ import {
|
||||
Tree,
|
||||
visitNotIgnoredFiles,
|
||||
} from '@nrwl/devkit';
|
||||
import { addPropertyToJestConfig } from '@nrwl/jest';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
|
||||
export default async function eslint8Updates(tree: Tree) {
|
||||
try {
|
||||
const { addPropertyToJestConfig } = await import('@nrwl/jest');
|
||||
const existingJestConfigPath = normalizePath(
|
||||
'tools/eslint-rules/jest.config.js'
|
||||
);
|
||||
|
||||
@ -9,11 +9,12 @@ import {
|
||||
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
||||
import { exampleRootTslintJson } from '@nrwl/linter';
|
||||
import { conversionGenerator } from './convert-tslint-to-eslint';
|
||||
import * as devkit from '@nrwl/devkit';
|
||||
|
||||
/**
|
||||
* Don't run actual child_process implementation of installPackagesTask()
|
||||
*/
|
||||
jest.mock('child_process');
|
||||
// jest.mock('child_process');
|
||||
|
||||
const appProjectName = 'nest-app-1';
|
||||
const appProjectRoot = `apps/${appProjectName}`;
|
||||
@ -101,6 +102,7 @@ describe('convert-tslint-to-eslint', () => {
|
||||
let host: Tree;
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.spyOn(devkit, 'installPackagesTask');
|
||||
host = createTreeWithEmptyV1Workspace();
|
||||
|
||||
writeJson(host, 'tslint.json', exampleRootTslintJson.raw);
|
||||
|
||||
@ -289,6 +289,9 @@ export async function generate(cwd: string, args: { [k: string]: any }) {
|
||||
'generate',
|
||||
projectsConfiguration
|
||||
);
|
||||
if (opts.dryRun) {
|
||||
process.env.NX_DRY_RUN = 'true';
|
||||
}
|
||||
const { normalizedGeneratorName, schema, implementationFactory, aliases } =
|
||||
ws.readGenerator(opts.collectionName, opts.generatorName);
|
||||
|
||||
|
||||
@ -22,8 +22,8 @@ export async function createAllStories(
|
||||
const projects = getProjects(tree);
|
||||
const projectConfiguration = projects.get(projectName);
|
||||
|
||||
const { sourceRoot, root } = projectConfiguration;
|
||||
const projectPath = projectRootPath(projectConfiguration);
|
||||
const { sourceRoot } = projectConfiguration;
|
||||
const projectPath = await projectRootPath(tree, projectConfiguration);
|
||||
|
||||
let componentPaths: string[] = [];
|
||||
visitNotIgnoredFiles(tree, projectPath, (path) => {
|
||||
|
||||
@ -71,6 +71,12 @@
|
||||
"version": "15.3.0-beta.0",
|
||||
"description": "Update projects using @nrwl/web:rollup to @nrwl/rollup:rollup for build.",
|
||||
"factory": "./src/migrations/update-15-3-0/update-rollup-executor"
|
||||
},
|
||||
"install-webpack-rollup-dependencies": {
|
||||
"cli": "nx",
|
||||
"version": "15.3.0-beta.0",
|
||||
"description": "Install new dependencies for React projects using Webpack or Rollup.",
|
||||
"factory": "./src/migrations/update-15-3-0/install-webpack-rollup-dependencies"
|
||||
}
|
||||
},
|
||||
"packageJsonUpdates": {
|
||||
|
||||
@ -31,32 +31,12 @@
|
||||
"migrations": "./migrations.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@nrwl/cypress": "file:../cypress",
|
||||
"@nrwl/devkit": "file:../devkit",
|
||||
"@nrwl/jest": "file:../jest",
|
||||
"@nrwl/js": "file:../js",
|
||||
"@nrwl/linter": "file:../linter",
|
||||
"@nrwl/storybook": "file:../storybook",
|
||||
"@nrwl/vite": "file:../vite",
|
||||
"@nrwl/web": "file:../web",
|
||||
"@nrwl/webpack": "file:../webpack",
|
||||
"@nrwl/workspace": "file:../workspace",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
|
||||
"@phenomnomnominal/tsquery": "4.1.1",
|
||||
"@svgr/webpack": "^6.1.2",
|
||||
"chalk": "4.1.0",
|
||||
"css-loader": "^6.4.0",
|
||||
"minimatch": "3.0.5",
|
||||
"react-refresh": "^0.10.0",
|
||||
"semver": "7.3.4",
|
||||
"style-loader": "^3.3.0",
|
||||
"stylus": "^0.55.0",
|
||||
"stylus-loader": "^7.1.0",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-merge": "^5.8.0"
|
||||
"semver": "7.3.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@ -3,8 +3,10 @@ import devServerExecutor from '@nrwl/webpack/src/executors/dev-server/dev-server
|
||||
import { WebDevServerOptions } from '@nrwl/webpack/src/executors/dev-server/schema';
|
||||
import { join } from 'path';
|
||||
import * as chalk from 'chalk';
|
||||
import { combineAsyncIterableIterators } from '@nrwl/js/src/utils/async-iterable/combine-async-iteratable-iterators';
|
||||
import { tapAsyncIterator } from '@nrwl/js/src/utils/async-iterable/tap-async-iteratable';
|
||||
import {
|
||||
combineAsyncIterableIterators,
|
||||
tapAsyncIterable,
|
||||
} from '@nrwl/devkit/src/utils/async-iterable';
|
||||
|
||||
type ModuleFederationDevServerOptions = WebDevServerOptions & {
|
||||
devRemotes?: string | string[];
|
||||
@ -65,7 +67,7 @@ export default async function* moduleFederationDevServer(
|
||||
}
|
||||
|
||||
let numAwaiting = knownRemotes.length + 1; // remotes + host
|
||||
return yield* tapAsyncIterator(iter, (x) => {
|
||||
return yield* tapAsyncIterable(iter, (x) => {
|
||||
numAwaiting--;
|
||||
if (numAwaiting === 0) {
|
||||
logger.info(
|
||||
|
||||
@ -15,6 +15,7 @@ import { addStyledModuleDependencies } from '../../rules/add-styled-dependencies
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
convertNxGenerator,
|
||||
ensurePackage,
|
||||
formatFiles,
|
||||
GeneratorCallback,
|
||||
joinPathFragments,
|
||||
@ -24,10 +25,12 @@ import {
|
||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||
import reactInitGenerator from '../init/init';
|
||||
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
||||
import { swcLoaderVersion } from '@nrwl/webpack/src/utils/versions';
|
||||
import { viteConfigurationGenerator, vitestGenerator } from '@nrwl/vite';
|
||||
import { mapLintPattern } from '@nrwl/linter/src/generators/lint-project/lint-project';
|
||||
import {
|
||||
nxVersion,
|
||||
swcCoreVersion,
|
||||
swcLoaderVersion,
|
||||
} from '../../utils/versions';
|
||||
|
||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
@ -90,6 +93,8 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
||||
addProject(host, options);
|
||||
|
||||
if (options.bundler === 'vite') {
|
||||
await ensurePackage(host, '@nrwl/vite', nxVersion);
|
||||
const { viteConfigurationGenerator } = await import('@nrwl/vite');
|
||||
// We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development.
|
||||
// See: https://vitejs.dev/guide/env-and-mode.html
|
||||
host.delete(joinPathFragments(options.appProjectRoot, 'src/environments'));
|
||||
@ -101,9 +106,20 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
||||
includeVitest: true,
|
||||
});
|
||||
tasks.push(viteTask);
|
||||
} else if (options.bundler === 'webpack') {
|
||||
await ensurePackage(host, '@nrwl/webpack', nxVersion);
|
||||
|
||||
const { webpackInitGenerator } = await import('@nrwl/webpack');
|
||||
const webpackInitTask = await webpackInitGenerator(host, {
|
||||
uiFramework: 'react',
|
||||
});
|
||||
tasks.push(webpackInitTask);
|
||||
}
|
||||
|
||||
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
|
||||
await ensurePackage(host, '@nrwl/vite', nxVersion);
|
||||
const { vitestGenerator } = await import('@nrwl/vite');
|
||||
|
||||
const vitestTask = await vitestGenerator(host, {
|
||||
uiFramework: 'react',
|
||||
project: options.projectName,
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import { cypressProjectGenerator } from '@nrwl/cypress';
|
||||
import { Tree } from '@nrwl/devkit';
|
||||
import { ensurePackage, Tree } from '@nrwl/devkit';
|
||||
import { nxVersion } from '../../../utils/versions';
|
||||
import { NormalizedSchema } from '../schema';
|
||||
|
||||
export async function addCypress(host: Tree, options: NormalizedSchema) {
|
||||
if (options.e2eTestRunner !== 'cypress') {
|
||||
return () => {};
|
||||
}
|
||||
await ensurePackage(host, '@nrwl/cypress', nxVersion);
|
||||
const { cypressProjectGenerator } = await import('@nrwl/cypress');
|
||||
|
||||
return await cypressProjectGenerator(host, {
|
||||
...options,
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import { Tree } from '@nrwl/devkit';
|
||||
import { jestProjectGenerator } from '@nrwl/jest';
|
||||
import { ensurePackage, Tree } from '@nrwl/devkit';
|
||||
import { NormalizedSchema } from '../schema';
|
||||
import { nxVersion } from '../../../utils/versions';
|
||||
|
||||
export async function addJest(host: Tree, options: NormalizedSchema) {
|
||||
await ensurePackage(host, '@nrwl/jest', nxVersion);
|
||||
const { jestProjectGenerator } = await import('@nrwl/jest');
|
||||
|
||||
if (options.unitTestRunner !== 'jest') {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ describe(componentTestGenerator.name, () => {
|
||||
component: true,
|
||||
});
|
||||
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'lib/some-lib.tsx',
|
||||
});
|
||||
@ -47,7 +47,7 @@ describe(componentTestGenerator.name, () => {
|
||||
js: true,
|
||||
});
|
||||
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'lib/some-lib.js',
|
||||
});
|
||||
@ -67,7 +67,7 @@ describe(componentTestGenerator.name, () => {
|
||||
component: true,
|
||||
});
|
||||
tree.write('libs/some-lib/src/lib/some-lib.cy.tsx', 'existing content');
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'lib/some-lib.tsx',
|
||||
});
|
||||
@ -89,12 +89,12 @@ describe(componentTestGenerator.name, () => {
|
||||
component: true,
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
await expect(
|
||||
componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'lib/blah/abc-123.blah',
|
||||
});
|
||||
}).not.toThrow();
|
||||
})
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
it('should handle being provided the full path to the component', async () => {
|
||||
@ -109,7 +109,7 @@ describe(componentTestGenerator.name, () => {
|
||||
component: true,
|
||||
});
|
||||
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||
});
|
||||
@ -144,11 +144,11 @@ export interface AnotherCmpProps {
|
||||
}
|
||||
|
||||
export function AnotherCmp(props: AnotherCmpProps) {
|
||||
return <button onClick="{handleClick}">{props.text}</button>;
|
||||
return <button onClick='{handleClick}'>{props.text}</button>;
|
||||
}
|
||||
`
|
||||
);
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||
});
|
||||
@ -180,7 +180,7 @@ export function AnotherCmp() {
|
||||
}
|
||||
`
|
||||
);
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||
});
|
||||
@ -214,7 +214,7 @@ export interface AnotherCmpProps {
|
||||
}
|
||||
|
||||
export default function AnotherCmp(props: AnotherCmpProps) {
|
||||
return <button onClick="{handleClick}">{props.text}</button>;
|
||||
return <button onClick='{handleClick}'>{props.text}</button>;
|
||||
}
|
||||
|
||||
export function AnotherCmp2() {
|
||||
@ -222,7 +222,7 @@ export function AnotherCmp2() {
|
||||
}
|
||||
`
|
||||
);
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||
});
|
||||
@ -257,7 +257,7 @@ export interface AnotherCmpProps {
|
||||
}
|
||||
|
||||
export function AnotherCmp(props: AnotherCmpProps) {
|
||||
return <button onClick="{handleClick}">{props.text}</button>;
|
||||
return <button onClick='{handleClick}'>{props.text}</button>;
|
||||
}
|
||||
|
||||
export function AnotherCmp2() {
|
||||
@ -265,7 +265,7 @@ export function AnotherCmp2() {
|
||||
}
|
||||
`
|
||||
);
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||
});
|
||||
@ -302,11 +302,11 @@ export interface AnotherCmpProps {
|
||||
}
|
||||
|
||||
export function AnotherCmp(props: AnotherCmpProps) {
|
||||
return <button onClick="{handleClick}">{props.text}</button>;
|
||||
return <button onClick='{handleClick}'>{props.text}</button>;
|
||||
}
|
||||
`
|
||||
);
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||
});
|
||||
@ -328,7 +328,7 @@ export function AnotherCmp(props: AnotherCmpProps) {
|
||||
unitTestRunner: 'none',
|
||||
component: true,
|
||||
});
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||
});
|
||||
@ -362,11 +362,11 @@ export interface AnotherCmpProps {
|
||||
}
|
||||
|
||||
export default function AnotherCmp(props: AnotherCmpProps) {
|
||||
return <button onClick="{handleClick}">{props.text}</button>;
|
||||
return <button onClick='{handleClick}'>{props.text}</button>;
|
||||
}
|
||||
`
|
||||
);
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||
});
|
||||
@ -400,11 +400,11 @@ export interface AnotherCmpProps {
|
||||
}
|
||||
|
||||
export function AnotherCmp(props: AnotherCmpProps) {
|
||||
return <button onClick="{handleClick}">{props.text}</button>;
|
||||
return <button onClick='{handleClick}'>{props.text}</button>;
|
||||
}
|
||||
`
|
||||
);
|
||||
componentTestGenerator(tree, {
|
||||
await componentTestGenerator(tree, {
|
||||
project: 'some-lib',
|
||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { assertMinimumCypressVersion } from '@nrwl/cypress/src/utils/cypress-version';
|
||||
import {
|
||||
ensurePackage,
|
||||
generateFiles,
|
||||
joinPathFragments,
|
||||
readProjectConfiguration,
|
||||
@ -12,12 +12,17 @@ import {
|
||||
getComponentNode,
|
||||
} from '../../utils/ast-utils';
|
||||
import { getDefaultsForComponent } from '../../utils/component-props';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { ComponentTestSchema } from './schema';
|
||||
|
||||
export function componentTestGenerator(
|
||||
export async function componentTestGenerator(
|
||||
tree: Tree,
|
||||
options: ComponentTestSchema
|
||||
) {
|
||||
await ensurePackage(tree, '@nrwl/cypress', nxVersion);
|
||||
const { assertMinimumCypressVersion } = await import(
|
||||
'@nrwl/cypress/src/utils/cypress-version'
|
||||
);
|
||||
assertMinimumCypressVersion(10);
|
||||
|
||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
import { cypressComponentProject } from '@nrwl/cypress';
|
||||
import { formatFiles, readProjectConfiguration, Tree } from '@nrwl/devkit';
|
||||
import {
|
||||
ensurePackage,
|
||||
formatFiles,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { addFiles } from './lib/add-files';
|
||||
import { updateProjectConfig } from './lib/update-configs';
|
||||
import { CypressComponentConfigurationSchema } from './schema.d';
|
||||
@ -13,6 +18,8 @@ export async function cypressComponentConfigGenerator(
|
||||
tree: Tree,
|
||||
options: CypressComponentConfigurationSchema
|
||||
) {
|
||||
await ensurePackage(tree, '@nrwl/cypress', nxVersion);
|
||||
const { cypressComponentProject } = await import('@nrwl/cypress');
|
||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||
const installTask = await cypressComponentProject(tree, {
|
||||
project: options.project,
|
||||
@ -20,7 +27,7 @@ export async function cypressComponentConfigGenerator(
|
||||
});
|
||||
|
||||
await updateProjectConfig(tree, options);
|
||||
addFiles(tree, projectConfig, options);
|
||||
await addFiles(tree, projectConfig, options);
|
||||
if (options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import { CypressComponentConfigurationSchema } from '../schema';
|
||||
const allowedFileExt = new RegExp(/\.[jt]sx?/g);
|
||||
const isSpecFile = new RegExp(/(spec|test)\./g);
|
||||
|
||||
export function addFiles(
|
||||
export async function addFiles(
|
||||
tree: Tree,
|
||||
projectConfig: ProjectConfiguration,
|
||||
options: CypressComponentConfigurationSchema
|
||||
@ -36,14 +36,19 @@ export function addFiles(
|
||||
);
|
||||
|
||||
if (options.generateTests) {
|
||||
const filePaths = [];
|
||||
visitNotIgnoredFiles(tree, projectConfig.sourceRoot, (filePath) => {
|
||||
if (isComponent(tree, filePath)) {
|
||||
componentTestGenerator(tree, {
|
||||
filePaths.push(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
for (const filePath of filePaths) {
|
||||
await componentTestGenerator(tree, {
|
||||
project: options.project,
|
||||
componentPath: filePath,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
import { findBuildConfig } from '@nrwl/cypress/src/utils/find-target-options';
|
||||
import {
|
||||
joinPathFragments,
|
||||
ProjectConfiguration,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
import { CypressComponentConfigurationSchema } from '../schema';
|
||||
@ -13,6 +9,9 @@ export async function updateProjectConfig(
|
||||
tree: Tree,
|
||||
options: CypressComponentConfigurationSchema
|
||||
) {
|
||||
const { findBuildConfig } = await import(
|
||||
'@nrwl/cypress/src/utils/find-target-options'
|
||||
);
|
||||
const found = await findBuildConfig(tree, {
|
||||
project: options.project,
|
||||
buildTarget: options.buildTarget,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { NxJsonConfiguration, readJson, Tree } from '@nrwl/devkit';
|
||||
import { readJson, Tree } from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
||||
import reactInitGenerator from './init';
|
||||
import { InitSchema } from './schema';
|
||||
@ -30,4 +30,9 @@ describe('init', () => {
|
||||
await reactInitGenerator(tree, { ...schema, unitTestRunner: 'none' });
|
||||
expect(tree.exists('jest.config.js')).toEqual(false);
|
||||
});
|
||||
|
||||
it('should not add babel.config.json if skipBabelConfig is true', async () => {
|
||||
await reactInitGenerator(tree, { ...schema, skipBabelConfig: true });
|
||||
expect(tree.exists('babel.config.json')).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
import { cypressInitGenerator } from '@nrwl/cypress';
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
convertNxGenerator,
|
||||
ensurePackage,
|
||||
GeneratorCallback,
|
||||
readWorkspaceConfiguration,
|
||||
removeDependenciesFromPackageJson,
|
||||
Tree,
|
||||
updateWorkspaceConfiguration,
|
||||
writeJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { webInitGenerator } from '@nrwl/web';
|
||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||
import {
|
||||
babelPresetReactVersion,
|
||||
nxVersion,
|
||||
reactDomVersion,
|
||||
reactTestRendererVersion,
|
||||
@ -66,22 +67,54 @@ function updateDependencies(host: Tree, schema: InitSchema) {
|
||||
});
|
||||
}
|
||||
|
||||
function initRootBabelConfig(tree: Tree, schema: InitSchema) {
|
||||
if (tree.exists('/babel.config.json') || tree.exists('/babel.config.js')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!schema.skipBabelConfig) {
|
||||
writeJson(tree, '/babel.config.json', {
|
||||
babelrcRoots: ['*'], // Make sure .babelrc files other than root can be loaded in a monorepo
|
||||
});
|
||||
}
|
||||
|
||||
const workspaceConfiguration = readWorkspaceConfiguration(tree);
|
||||
|
||||
if (workspaceConfiguration.namedInputs?.sharedGlobals) {
|
||||
workspaceConfiguration.namedInputs.sharedGlobals.push(
|
||||
'{workspaceRoot}/babel.config.json'
|
||||
);
|
||||
}
|
||||
updateWorkspaceConfiguration(tree, workspaceConfiguration);
|
||||
}
|
||||
|
||||
export async function reactInitGenerator(host: Tree, schema: InitSchema) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
setDefault(host);
|
||||
|
||||
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') {
|
||||
await ensurePackage(host, '@nrwl/cypress', nxVersion);
|
||||
const { cypressInitGenerator } = await import('@nrwl/cypress');
|
||||
const cypressTask = cypressInitGenerator(host, {});
|
||||
tasks.push(cypressTask);
|
||||
}
|
||||
|
||||
// TODO(jack): We should be able to remove this generator and have react init everything.
|
||||
const initTask = await webInitGenerator(host, {
|
||||
...schema,
|
||||
skipPackageJson: true,
|
||||
});
|
||||
tasks.push(initTask);
|
||||
if (!schema.skipPackageJson && !schema.skipBabelConfig) {
|
||||
const installBabelTask = addDependenciesToPackageJson(
|
||||
host,
|
||||
{},
|
||||
{
|
||||
'@babel/preset-react': babelPresetReactVersion,
|
||||
}
|
||||
);
|
||||
tasks.push(installBabelTask);
|
||||
}
|
||||
|
||||
if (!schema.skipBabelConfig) {
|
||||
initRootBabelConfig(host, schema);
|
||||
}
|
||||
|
||||
if (!schema.skipPackageJson) {
|
||||
const installTask = updateDependencies(host, schema);
|
||||
tasks.push(installTask);
|
||||
|
||||
47
packages/react/src/generators/library/lib/add-linting.ts
Normal file
47
packages/react/src/generators/library/lib/add-linting.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { Tree } from 'nx/src/generators/tree';
|
||||
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||
import { joinPathFragments } from 'nx/src/utils/path';
|
||||
import { updateJson } from 'nx/src/generators/utils/json';
|
||||
import { addDependenciesToPackageJson } from '@nrwl/devkit';
|
||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||
|
||||
import { NormalizedSchema } from '../schema';
|
||||
import {
|
||||
extendReactEslintJson,
|
||||
extraEslintDependencies,
|
||||
} from '../../../utils/lint';
|
||||
|
||||
export async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||
if (options.linter === Linter.EsLint) {
|
||||
const lintTask = await lintProjectGenerator(host, {
|
||||
linter: options.linter,
|
||||
project: options.name,
|
||||
tsConfigPaths: [
|
||||
joinPathFragments(options.projectRoot, 'tsconfig.lib.json'),
|
||||
],
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
eslintFilePatterns: [`${options.projectRoot}/**/*.{ts,tsx,js,jsx}`],
|
||||
skipFormat: true,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
});
|
||||
|
||||
updateJson(
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, '.eslintrc.json'),
|
||||
extendReactEslintJson
|
||||
);
|
||||
|
||||
let installTask = () => {};
|
||||
if (!options.skipPackageJson) {
|
||||
installTask = await addDependenciesToPackageJson(
|
||||
host,
|
||||
extraEslintDependencies.dependencies,
|
||||
extraEslintDependencies.devDependencies
|
||||
);
|
||||
}
|
||||
|
||||
return runTasksInSerial(lintTask, installTask);
|
||||
} else {
|
||||
return () => {};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
import { Tree } from 'nx/src/generators/tree';
|
||||
import {
|
||||
ensurePackage,
|
||||
getWorkspaceLayout,
|
||||
joinPathFragments,
|
||||
readProjectConfiguration,
|
||||
updateProjectConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
|
||||
import { maybeJs } from './maybe-js';
|
||||
import { NormalizedSchema } from '../schema';
|
||||
import { nxVersion } from '../../../utils/versions';
|
||||
|
||||
export async function addRollupBuildTarget(
|
||||
host: Tree,
|
||||
options: NormalizedSchema
|
||||
) {
|
||||
await ensurePackage(host, '@nrwl/rollup', nxVersion);
|
||||
const { rollupInitGenerator } = await import('@nrwl/rollup');
|
||||
|
||||
const { targets } = readProjectConfiguration(host, options.name);
|
||||
|
||||
const { libsDir } = getWorkspaceLayout(host);
|
||||
const external: string[] = [];
|
||||
|
||||
if (options.style === '@emotion/styled') {
|
||||
external.push('@emotion/react/jsx-runtime');
|
||||
} else {
|
||||
external.push('react/jsx-runtime');
|
||||
}
|
||||
|
||||
targets.build = {
|
||||
executor: '@nrwl/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
outputPath:
|
||||
libsDir !== '.'
|
||||
? `dist/${libsDir}/${options.projectDirectory}`
|
||||
: `dist/${options.projectDirectory}`,
|
||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||
project: `${options.projectRoot}/package.json`,
|
||||
entryFile: maybeJs(options, `${options.projectRoot}/src/index.ts`),
|
||||
external,
|
||||
rollupConfig: `@nrwl/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,
|
||||
});
|
||||
|
||||
return rollupInitGenerator(host, options);
|
||||
}
|
||||
74
packages/react/src/generators/library/lib/create-files.ts
Normal file
74
packages/react/src/generators/library/lib/create-files.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { Tree } from 'nx/src/generators/tree';
|
||||
import {
|
||||
generateFiles,
|
||||
joinPathFragments,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
toJS,
|
||||
updateJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
||||
|
||||
import { NormalizedSchema } from '../schema';
|
||||
|
||||
export function createFiles(host: Tree, options: NormalizedSchema) {
|
||||
const substitutions = {
|
||||
...options,
|
||||
...names(options.name),
|
||||
tmpl: '',
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||
rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot),
|
||||
};
|
||||
|
||||
generateFiles(
|
||||
host,
|
||||
joinPathFragments(__dirname, '../files/common'),
|
||||
options.projectRoot,
|
||||
substitutions
|
||||
);
|
||||
|
||||
if (options.bundler === 'vite') {
|
||||
generateFiles(
|
||||
host,
|
||||
joinPathFragments(__dirname, '../files/vite'),
|
||||
options.projectRoot,
|
||||
substitutions
|
||||
);
|
||||
|
||||
if (host.exists(joinPathFragments(options.projectRoot, '.babelrc'))) {
|
||||
host.delete(joinPathFragments(options.projectRoot, '.babelrc'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.publishable && !options.buildable) {
|
||||
host.delete(`${options.projectRoot}/package.json`);
|
||||
}
|
||||
|
||||
if (options.js) {
|
||||
toJS(host);
|
||||
}
|
||||
|
||||
updateTsConfig(host, options);
|
||||
}
|
||||
|
||||
function updateTsConfig(tree: Tree, options: NormalizedSchema) {
|
||||
updateJson(
|
||||
tree,
|
||||
joinPathFragments(options.projectRoot, 'tsconfig.json'),
|
||||
(json) => {
|
||||
if (options.strict) {
|
||||
json.compilerOptions = {
|
||||
...json.compilerOptions,
|
||||
forceConsistentCasingInFileNames: true,
|
||||
strict: true,
|
||||
noImplicitOverride: true,
|
||||
noPropertyAccessFromIndexSignature: true,
|
||||
noImplicitReturns: true,
|
||||
noFallthroughCasesInSwitch: true,
|
||||
};
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
);
|
||||
}
|
||||
7
packages/react/src/generators/library/lib/maybe-js.ts
Normal file
7
packages/react/src/generators/library/lib/maybe-js.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { NormalizedSchema } from '../schema';
|
||||
|
||||
export function maybeJs(options: NormalizedSchema, path: string): string {
|
||||
return options.js && (path.endsWith('.ts') || path.endsWith('.tsx'))
|
||||
? path.replace(/\.tsx?$/, '.js')
|
||||
: path;
|
||||
}
|
||||
@ -9,8 +9,7 @@ import {
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import { assertValidStyle } from '../../../utils/assertion';
|
||||
import { NormalizedSchema } from '../library';
|
||||
import { Schema } from '../schema';
|
||||
import { NormalizedSchema, Schema } from '../schema';
|
||||
|
||||
export function normalizeOptions(
|
||||
host: Tree,
|
||||
@ -40,7 +39,9 @@ export function normalizeOptions(
|
||||
const normalized = {
|
||||
...options,
|
||||
compiler: options.compiler ?? 'babel',
|
||||
bundler: options.bundler ?? 'none',
|
||||
bundler:
|
||||
options.bundler ??
|
||||
(options.buildable || options.publishable ? 'rollup' : 'none'),
|
||||
fileName,
|
||||
routePath: `/${name}`,
|
||||
name: projectName,
|
||||
|
||||
111
packages/react/src/generators/library/lib/update-app-routes.ts
Normal file
111
packages/react/src/generators/library/lib/update-app-routes.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
applyChangesToString,
|
||||
getWorkspaceLayout,
|
||||
names,
|
||||
} from '@nrwl/devkit';
|
||||
import { Tree } from 'nx/src/generators/tree';
|
||||
import { getImportPath, joinPathFragments } from 'nx/src/utils/path';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import { NormalizedSchema } from '../schema';
|
||||
import {
|
||||
addBrowserRouter,
|
||||
addInitialRoutes,
|
||||
addRoute,
|
||||
findComponentImportPath,
|
||||
} from '../../../utils/ast-utils';
|
||||
import { maybeJs } from './maybe-js';
|
||||
import {
|
||||
reactRouterDomVersion,
|
||||
typesReactRouterDomVersion,
|
||||
} from '../../../utils/versions';
|
||||
|
||||
export function updateAppRoutes(host: Tree, options: NormalizedSchema) {
|
||||
if (!options.appMain || !options.appSourceRoot) {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const { content, source } = readComponent(host, options.appMain);
|
||||
|
||||
const componentImportPath = findComponentImportPath('App', source);
|
||||
|
||||
if (!componentImportPath) {
|
||||
throw new Error(
|
||||
`Could not find App component in ${options.appMain} (Hint: you can omit --appProject, or make sure App exists)`
|
||||
);
|
||||
}
|
||||
|
||||
const appComponentPath = joinPathFragments(
|
||||
options.appSourceRoot,
|
||||
maybeJs(options, `${componentImportPath}.tsx`)
|
||||
);
|
||||
|
||||
const routerTask = addDependenciesToPackageJson(
|
||||
host,
|
||||
{ 'react-router-dom': reactRouterDomVersion },
|
||||
{ '@types/react-router-dom': typesReactRouterDomVersion }
|
||||
);
|
||||
|
||||
// addBrowserRouterToMain
|
||||
const isRouterPresent = content.match(/react-router-dom/);
|
||||
if (!isRouterPresent) {
|
||||
const changes = applyChangesToString(
|
||||
content,
|
||||
addBrowserRouter(options.appMain, source)
|
||||
);
|
||||
host.write(options.appMain, changes);
|
||||
}
|
||||
|
||||
// addInitialAppRoutes
|
||||
{
|
||||
const { content: componentContent, source: componentSource } =
|
||||
readComponent(host, appComponentPath);
|
||||
const isComponentRouterPresent = componentContent.match(/react-router-dom/);
|
||||
if (!isComponentRouterPresent) {
|
||||
const changes = applyChangesToString(
|
||||
componentContent,
|
||||
addInitialRoutes(appComponentPath, componentSource)
|
||||
);
|
||||
host.write(appComponentPath, changes);
|
||||
}
|
||||
}
|
||||
|
||||
// addNewAppRoute
|
||||
{
|
||||
const { content: componentContent, source: componentSource } =
|
||||
readComponent(host, appComponentPath);
|
||||
const { npmScope } = getWorkspaceLayout(host);
|
||||
const changes = applyChangesToString(
|
||||
componentContent,
|
||||
addRoute(appComponentPath, componentSource, {
|
||||
routePath: options.routePath,
|
||||
componentName: names(options.name).className,
|
||||
moduleName: getImportPath(npmScope, options.projectDirectory),
|
||||
})
|
||||
);
|
||||
host.write(appComponentPath, changes);
|
||||
}
|
||||
|
||||
return routerTask;
|
||||
}
|
||||
|
||||
function readComponent(
|
||||
host: Tree,
|
||||
path: string
|
||||
): { content: string; source: ts.SourceFile } {
|
||||
if (!host.exists(path)) {
|
||||
throw new Error(`Cannot find ${path}`);
|
||||
}
|
||||
|
||||
const content = host.read(path, 'utf-8');
|
||||
|
||||
const source = ts.createSourceFile(
|
||||
path,
|
||||
content,
|
||||
ts.ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
return { content, source };
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
import { Tree } from 'nx/src/generators/tree';
|
||||
import { updateJson } from 'nx/src/generators/utils/json';
|
||||
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
|
||||
import { getWorkspaceLayout, joinPathFragments } from '@nrwl/devkit';
|
||||
|
||||
import { NormalizedSchema } from '../schema';
|
||||
import { maybeJs } from './maybe-js';
|
||||
|
||||
export function updateBaseTsConfig(host: Tree, options: NormalizedSchema) {
|
||||
updateJson(host, getRootTsConfigPathInTree(host), (json) => {
|
||||
const c = json.compilerOptions;
|
||||
c.paths = c.paths || {};
|
||||
delete c.paths[options.name];
|
||||
|
||||
if (c.paths[options.importPath]) {
|
||||
throw new Error(
|
||||
`You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.`
|
||||
);
|
||||
}
|
||||
|
||||
const { libsDir } = getWorkspaceLayout(host);
|
||||
|
||||
c.paths[options.importPath] = [
|
||||
maybeJs(
|
||||
options,
|
||||
joinPathFragments(libsDir, `${options.projectDirectory}/src/index.ts`)
|
||||
),
|
||||
];
|
||||
|
||||
return json;
|
||||
});
|
||||
}
|
||||
@ -11,6 +11,7 @@ import {
|
||||
createTreeWithEmptyWorkspace,
|
||||
} from '@nrwl/devkit/testing';
|
||||
import { Linter } from '@nrwl/linter';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import applicationGenerator from '../application/application';
|
||||
import libraryGenerator from './library';
|
||||
import { Schema } from './schema';
|
||||
@ -37,6 +38,16 @@ describe('lib', () => {
|
||||
beforeEach(() => {
|
||||
mockedInstalledCypressVersion.mockReturnValue(10);
|
||||
tree = createTreeWithEmptyV1Workspace();
|
||||
updateJson(tree, '/package.json', (json) => {
|
||||
json.devDependencies = {
|
||||
'@nrwl/cypress': nxVersion,
|
||||
'@nrwl/jest': nxVersion,
|
||||
'@nrwl/rollup': nxVersion,
|
||||
'@nrwl/vite': nxVersion,
|
||||
'@nrwl/webpack': nxVersion,
|
||||
};
|
||||
return json;
|
||||
});
|
||||
});
|
||||
|
||||
describe('not nested', () => {
|
||||
@ -726,7 +737,6 @@ describe('lib', () => {
|
||||
describe('--skipPackageJson', () => {
|
||||
it('should not add dependencies to package.json when true', async () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
const packageJsonBeforeGenerator = tree.read('package.json', 'utf-8');
|
||||
// ACT
|
||||
await libraryGenerator(tree, {
|
||||
|
||||
@ -1,64 +1,32 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
addProjectConfiguration,
|
||||
applyChangesToString,
|
||||
convertNxGenerator,
|
||||
ensurePackage,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
GeneratorCallback,
|
||||
getWorkspaceLayout,
|
||||
joinPathFragments,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
toJS,
|
||||
Tree,
|
||||
updateJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { getImportPath } from 'nx/src/utils/path';
|
||||
import { jestProjectGenerator } from '@nrwl/jest';
|
||||
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
||||
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||
|
||||
import {
|
||||
getRelativePathToRootTsConfig,
|
||||
getRootTsConfigPathInTree,
|
||||
} from '@nrwl/workspace/src/utilities/typescript';
|
||||
import * as ts from 'typescript';
|
||||
import {
|
||||
addBrowserRouter,
|
||||
addInitialRoutes,
|
||||
addRoute,
|
||||
findComponentImportPath,
|
||||
} from '../../utils/ast-utils';
|
||||
import {
|
||||
extendReactEslintJson,
|
||||
extraEslintDependencies,
|
||||
} from '../../utils/lint';
|
||||
import {
|
||||
nxVersion,
|
||||
reactDomVersion,
|
||||
reactRouterDomVersion,
|
||||
reactVersion,
|
||||
typesReactRouterDomVersion,
|
||||
swcCoreVersion,
|
||||
} from '../../utils/versions';
|
||||
import componentGenerator from '../component/component';
|
||||
import initGenerator from '../init/init';
|
||||
import { Schema } from './schema';
|
||||
import { updateJestConfigContent } from '../../utils/jest-utils';
|
||||
import { viteConfigurationGenerator, vitestGenerator } from '@nrwl/vite';
|
||||
import { normalizeOptions } from './lib/normalize-options';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
fileName: string;
|
||||
projectRoot: string;
|
||||
routePath: string;
|
||||
projectDirectory: string;
|
||||
parsedTags: string[];
|
||||
appMain?: string;
|
||||
appSourceRoot?: string;
|
||||
libsDir?: string;
|
||||
unitTestRunner: 'jest' | 'vitest' | 'none';
|
||||
}
|
||||
import { addRollupBuildTarget } from './lib/add-rollup-build-target';
|
||||
import { addLinting } from './lib/add-linting';
|
||||
import { updateAppRoutes } from './lib/update-app-routes';
|
||||
import { createFiles } from './lib/create-files';
|
||||
import { updateBaseTsConfig } from './lib/update-base-tsconfig';
|
||||
|
||||
export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
@ -82,7 +50,18 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||
});
|
||||
tasks.push(initTask);
|
||||
|
||||
addProject(host, options);
|
||||
addProjectConfiguration(
|
||||
host,
|
||||
options.name,
|
||||
{
|
||||
root: options.projectRoot,
|
||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||
projectType: 'library',
|
||||
tags: options.parsedTags,
|
||||
targets: {},
|
||||
},
|
||||
options.standaloneConfig
|
||||
);
|
||||
|
||||
const lintTask = await addLinting(host, options);
|
||||
tasks.push(lintTask);
|
||||
@ -93,7 +72,10 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||
updateBaseTsConfig(host, options);
|
||||
}
|
||||
|
||||
// Set up build target
|
||||
if (options.buildable && options.bundler === 'vite') {
|
||||
await ensurePackage(host, '@nrwl/vite', nxVersion);
|
||||
const { viteConfigurationGenerator } = await import('@nrwl/vite');
|
||||
const viteTask = await viteConfigurationGenerator(host, {
|
||||
uiFramework: 'react',
|
||||
project: options.name,
|
||||
@ -103,9 +85,16 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||
includeVitest: true,
|
||||
});
|
||||
tasks.push(viteTask);
|
||||
} else if (options.buildable && options.bundler === 'rollup') {
|
||||
const rollupTask = await addRollupBuildTarget(host, options);
|
||||
tasks.push(rollupTask);
|
||||
}
|
||||
|
||||
// Set up test target
|
||||
if (options.unitTestRunner === 'jest') {
|
||||
await ensurePackage(host, '@nrwl/jest', nxVersion);
|
||||
const { jestProjectGenerator } = await import('@nrwl/jest');
|
||||
|
||||
const jestTask = await jestProjectGenerator(host, {
|
||||
...options,
|
||||
project: options.name,
|
||||
@ -129,6 +118,8 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||
options.unitTestRunner === 'vitest' &&
|
||||
options.bundler !== 'vite' // tests are already configured if bundler is vite
|
||||
) {
|
||||
await ensurePackage(host, '@nrwl/vite', nxVersion);
|
||||
const { vitestGenerator } = await import('@nrwl/vite');
|
||||
const vitestTask = await vitestGenerator(host, {
|
||||
uiFramework: 'react',
|
||||
project: options.name,
|
||||
@ -155,11 +146,14 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||
}
|
||||
|
||||
if (options.publishable || options.buildable) {
|
||||
updateLibPackageNpmScope(host, options);
|
||||
updateJson(host, `${options.projectRoot}/package.json`, (json) => {
|
||||
json.name = options.importPath;
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
if (!options.skipPackageJson) {
|
||||
const installTask = await addDependenciesToPackageJson(
|
||||
const installReactTask = await addDependenciesToPackageJson(
|
||||
host,
|
||||
{
|
||||
react: reactVersion,
|
||||
@ -167,7 +161,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||
},
|
||||
options.compiler === 'swc' ? { '@swc/core': swcCoreVersion } : {}
|
||||
);
|
||||
tasks.push(installTask);
|
||||
tasks.push(installReactTask);
|
||||
}
|
||||
|
||||
const routeTask = updateAppRoutes(host, options);
|
||||
@ -180,281 +174,5 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||
if (options.linter === Linter.EsLint) {
|
||||
const lintTask = await lintProjectGenerator(host, {
|
||||
linter: options.linter,
|
||||
project: options.name,
|
||||
tsConfigPaths: [
|
||||
joinPathFragments(options.projectRoot, 'tsconfig.lib.json'),
|
||||
],
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
eslintFilePatterns: [`${options.projectRoot}/**/*.{ts,tsx,js,jsx}`],
|
||||
skipFormat: true,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
});
|
||||
|
||||
updateJson(
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, '.eslintrc.json'),
|
||||
extendReactEslintJson
|
||||
);
|
||||
|
||||
let installTask = () => {};
|
||||
if (!options.skipPackageJson) {
|
||||
installTask = await addDependenciesToPackageJson(
|
||||
host,
|
||||
extraEslintDependencies.dependencies,
|
||||
extraEslintDependencies.devDependencies
|
||||
);
|
||||
}
|
||||
|
||||
return runTasksInSerial(lintTask, installTask);
|
||||
} else {
|
||||
return () => {};
|
||||
}
|
||||
}
|
||||
|
||||
function addProject(host: Tree, options: NormalizedSchema) {
|
||||
const targets: { [key: string]: any } = {};
|
||||
|
||||
if (options.publishable || options.buildable) {
|
||||
const { libsDir } = getWorkspaceLayout(host);
|
||||
const external: string[] = [];
|
||||
|
||||
if (options.style === '@emotion/styled') {
|
||||
external.push('@emotion/react/jsx-runtime');
|
||||
} else {
|
||||
external.push('react/jsx-runtime');
|
||||
}
|
||||
|
||||
targets.build = {
|
||||
executor: '@nrwl/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
outputPath:
|
||||
libsDir !== '.'
|
||||
? `dist/${libsDir}/${options.projectDirectory}`
|
||||
: `dist/${options.projectDirectory}`,
|
||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||
project: `${options.projectRoot}/package.json`,
|
||||
entryFile: maybeJs(options, `${options.projectRoot}/src/index.ts`),
|
||||
external,
|
||||
rollupConfig: `@nrwl/react/plugins/bundle-rollup`,
|
||||
compiler: options.compiler ?? 'babel',
|
||||
assets: [
|
||||
{
|
||||
glob: `${options.projectRoot}/README.md`,
|
||||
input: '.',
|
||||
output: '.',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
addProjectConfiguration(
|
||||
host,
|
||||
options.name,
|
||||
{
|
||||
root: options.projectRoot,
|
||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||
projectType: 'library',
|
||||
tags: options.parsedTags,
|
||||
targets,
|
||||
},
|
||||
options.standaloneConfig
|
||||
);
|
||||
}
|
||||
|
||||
function updateTsConfig(tree: Tree, options: NormalizedSchema) {
|
||||
updateJson(
|
||||
tree,
|
||||
joinPathFragments(options.projectRoot, 'tsconfig.json'),
|
||||
(json) => {
|
||||
if (options.strict) {
|
||||
json.compilerOptions = {
|
||||
...json.compilerOptions,
|
||||
forceConsistentCasingInFileNames: true,
|
||||
strict: true,
|
||||
noImplicitOverride: true,
|
||||
noPropertyAccessFromIndexSignature: true,
|
||||
noImplicitReturns: true,
|
||||
noFallthroughCasesInSwitch: true,
|
||||
};
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function updateBaseTsConfig(host: Tree, options: NormalizedSchema) {
|
||||
updateJson(host, getRootTsConfigPathInTree(host), (json) => {
|
||||
const c = json.compilerOptions;
|
||||
c.paths = c.paths || {};
|
||||
delete c.paths[options.name];
|
||||
|
||||
if (c.paths[options.importPath]) {
|
||||
throw new Error(
|
||||
`You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.`
|
||||
);
|
||||
}
|
||||
|
||||
const { libsDir } = getWorkspaceLayout(host);
|
||||
|
||||
c.paths[options.importPath] = [
|
||||
maybeJs(
|
||||
options,
|
||||
joinPathFragments(libsDir, `${options.projectDirectory}/src/index.ts`)
|
||||
),
|
||||
];
|
||||
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
function createFiles(host: Tree, options: NormalizedSchema) {
|
||||
const substitutions = {
|
||||
...options,
|
||||
...names(options.name),
|
||||
tmpl: '',
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||
rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot),
|
||||
};
|
||||
|
||||
generateFiles(
|
||||
host,
|
||||
joinPathFragments(__dirname, './files/common'),
|
||||
options.projectRoot,
|
||||
substitutions
|
||||
);
|
||||
|
||||
if (options.bundler === 'vite') {
|
||||
generateFiles(
|
||||
host,
|
||||
joinPathFragments(__dirname, './files/vite'),
|
||||
options.projectRoot,
|
||||
substitutions
|
||||
);
|
||||
|
||||
if (host.exists(joinPathFragments(options.projectRoot, '.babelrc'))) {
|
||||
host.delete(joinPathFragments(options.projectRoot, '.babelrc'));
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.publishable && !options.buildable) {
|
||||
host.delete(`${options.projectRoot}/package.json`);
|
||||
}
|
||||
|
||||
if (options.js) {
|
||||
toJS(host);
|
||||
}
|
||||
|
||||
updateTsConfig(host, options);
|
||||
}
|
||||
|
||||
function updateAppRoutes(host: Tree, options: NormalizedSchema) {
|
||||
if (!options.appMain || !options.appSourceRoot) {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const { content, source } = readComponent(host, options.appMain);
|
||||
|
||||
const componentImportPath = findComponentImportPath('App', source);
|
||||
|
||||
if (!componentImportPath) {
|
||||
throw new Error(
|
||||
`Could not find App component in ${options.appMain} (Hint: you can omit --appProject, or make sure App exists)`
|
||||
);
|
||||
}
|
||||
|
||||
const appComponentPath = joinPathFragments(
|
||||
options.appSourceRoot,
|
||||
maybeJs(options, `${componentImportPath}.tsx`)
|
||||
);
|
||||
|
||||
const routerTask = addDependenciesToPackageJson(
|
||||
host,
|
||||
{ 'react-router-dom': reactRouterDomVersion },
|
||||
{ '@types/react-router-dom': typesReactRouterDomVersion }
|
||||
);
|
||||
|
||||
// addBrowserRouterToMain
|
||||
const isRouterPresent = content.match(/react-router-dom/);
|
||||
if (!isRouterPresent) {
|
||||
const changes = applyChangesToString(
|
||||
content,
|
||||
addBrowserRouter(options.appMain, source)
|
||||
);
|
||||
host.write(options.appMain, changes);
|
||||
}
|
||||
|
||||
// addInitialAppRoutes
|
||||
{
|
||||
const { content: componentContent, source: componentSource } =
|
||||
readComponent(host, appComponentPath);
|
||||
const isComponentRouterPresent = componentContent.match(/react-router-dom/);
|
||||
if (!isComponentRouterPresent) {
|
||||
const changes = applyChangesToString(
|
||||
componentContent,
|
||||
addInitialRoutes(appComponentPath, componentSource)
|
||||
);
|
||||
host.write(appComponentPath, changes);
|
||||
}
|
||||
}
|
||||
|
||||
// addNewAppRoute
|
||||
{
|
||||
const { content: componentContent, source: componentSource } =
|
||||
readComponent(host, appComponentPath);
|
||||
const { npmScope } = getWorkspaceLayout(host);
|
||||
const changes = applyChangesToString(
|
||||
componentContent,
|
||||
addRoute(appComponentPath, componentSource, {
|
||||
routePath: options.routePath,
|
||||
componentName: names(options.name).className,
|
||||
moduleName: getImportPath(npmScope, options.projectDirectory),
|
||||
})
|
||||
);
|
||||
host.write(appComponentPath, changes);
|
||||
}
|
||||
|
||||
return routerTask;
|
||||
}
|
||||
|
||||
function readComponent(
|
||||
host: Tree,
|
||||
path: string
|
||||
): { content: string; source: ts.SourceFile } {
|
||||
if (!host.exists(path)) {
|
||||
throw new Error(`Cannot find ${path}`);
|
||||
}
|
||||
|
||||
const content = host.read(path, 'utf-8');
|
||||
|
||||
const source = ts.createSourceFile(
|
||||
path,
|
||||
content,
|
||||
ts.ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
return { content, source };
|
||||
}
|
||||
|
||||
function updateLibPackageNpmScope(host: Tree, options: NormalizedSchema) {
|
||||
return updateJson(host, `${options.projectRoot}/package.json`, (json) => {
|
||||
json.name = options.importPath;
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
function maybeJs(options: NormalizedSchema, path: string): string {
|
||||
return options.js && (path.endsWith('.ts') || path.endsWith('.tsx'))
|
||||
? path.replace(/\.tsx?$/, '.js')
|
||||
: path;
|
||||
}
|
||||
|
||||
export default libraryGenerator;
|
||||
export const librarySchematic = convertNxGenerator(libraryGenerator);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Linter } from '@nrwl/linter';
|
||||
import type { Linter } from '@nrwl/linter';
|
||||
import { SupportedStyles } from '../../../typings/style';
|
||||
|
||||
export interface Schema {
|
||||
@ -28,3 +28,17 @@ export interface Schema {
|
||||
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
||||
minimal?: boolean;
|
||||
}
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
js: boolean;
|
||||
name: string;
|
||||
fileName: string;
|
||||
projectRoot: string;
|
||||
routePath: string;
|
||||
projectDirectory: string;
|
||||
parsedTags: string[];
|
||||
appMain?: string;
|
||||
appSourceRoot?: string;
|
||||
libsDir?: string;
|
||||
unitTestRunner: 'jest' | 'vitest' | 'none';
|
||||
}
|
||||
|
||||
@ -15,10 +15,6 @@ import {
|
||||
visitNotIgnoredFiles,
|
||||
} from '@nrwl/devkit';
|
||||
import { basename, join } from 'path';
|
||||
import {
|
||||
findStorybookAndBuildTargetsAndCompiler,
|
||||
isTheFileAStory,
|
||||
} from '@nrwl/storybook/src/utils/utilities';
|
||||
import minimatch = require('minimatch');
|
||||
|
||||
export interface StorybookStoriesSchema {
|
||||
@ -29,7 +25,13 @@ export interface StorybookStoriesSchema {
|
||||
ignorePaths?: string[];
|
||||
}
|
||||
|
||||
export function projectRootPath(config: ProjectConfiguration): string {
|
||||
export async function projectRootPath(
|
||||
tree: Tree,
|
||||
config: ProjectConfiguration
|
||||
): Promise<string> {
|
||||
const { findStorybookAndBuildTargetsAndCompiler } = await import(
|
||||
'@nrwl/storybook/src/utils/utilities'
|
||||
);
|
||||
let projectDir: string;
|
||||
if (config.projectType === 'application') {
|
||||
const { nextBuildTarget } = findStorybookAndBuildTargetsAndCompiler(
|
||||
@ -79,12 +81,16 @@ export async function createAllStories(
|
||||
cypressProject?: string,
|
||||
ignorePaths?: string[]
|
||||
) {
|
||||
const { isTheFileAStory } = await import(
|
||||
'@nrwl/storybook/src/utils/utilities'
|
||||
);
|
||||
const projects = getProjects(tree);
|
||||
const projectConfiguration = projects.get(projectName);
|
||||
const { sourceRoot, root } = projectConfiguration;
|
||||
let componentPaths: string[] = [];
|
||||
|
||||
visitNotIgnoredFiles(tree, projectRootPath(projectConfiguration), (path) => {
|
||||
const projectPath = await projectRootPath(tree, projectConfiguration);
|
||||
visitNotIgnoredFiles(tree, projectPath, (path) => {
|
||||
// Ignore private files starting with "_".
|
||||
if (basename(path).startsWith('_')) return;
|
||||
|
||||
|
||||
@ -2,14 +2,18 @@ import { StorybookConfigureSchema } from './schema';
|
||||
import storiesGenerator from '../stories/stories';
|
||||
import {
|
||||
convertNxGenerator,
|
||||
ensurePackage,
|
||||
logger,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import { configurationGenerator } from '@nrwl/storybook';
|
||||
import { getE2eProjectName } from '@nrwl/cypress/src/utils/project-name';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
|
||||
async function generateStories(host: Tree, schema: StorybookConfigureSchema) {
|
||||
await ensurePackage(host, '@nrwl/cypress', nxVersion);
|
||||
const { getE2eProjectName } = await import(
|
||||
'@nrwl/cypress/src/utils/project-name'
|
||||
);
|
||||
const projectConfig = readProjectConfiguration(host, schema.name);
|
||||
const cypressProject = getE2eProjectName(
|
||||
schema.name,
|
||||
@ -30,6 +34,9 @@ export async function storybookConfigurationGenerator(
|
||||
host: Tree,
|
||||
schema: StorybookConfigureSchema
|
||||
) {
|
||||
await ensurePackage(host, '@nrwl/storybook', nxVersion);
|
||||
const { configurationGenerator } = await import('@nrwl/storybook');
|
||||
|
||||
let bundler = schema.bundler ?? 'webpack';
|
||||
const projectConfig = readProjectConfiguration(host, schema.name);
|
||||
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
import { readJson, Tree } from '@nrwl/devkit';
|
||||
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||
import * as path from 'path';
|
||||
import { removeReactReduxTypesFromPackageJson } from './remove-react-redux-types-package';
|
||||
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
||||
|
||||
describe('Remove @types/react-redux Package from package.json 12.0.0', () => {
|
||||
let tree: Tree;
|
||||
let schematicRunner: SchematicTestRunner;
|
||||
|
||||
beforeEach(async () => {
|
||||
tree = createTreeWithEmptyV1Workspace();
|
||||
|
||||
schematicRunner = new SchematicTestRunner(
|
||||
'@nrwl/react',
|
||||
path.join(__dirname, '../../../migrations.json')
|
||||
);
|
||||
});
|
||||
|
||||
it(`should remove @types/react-redux from deps and/or from devDeps in package.json`, async () => {
|
||||
tree.write(
|
||||
'package.json',
|
||||
JSON.stringify({
|
||||
dependencies: {
|
||||
'@types/react-redux': '10.1.1',
|
||||
},
|
||||
devDependencies: {
|
||||
'@types/react-redux': '10.1.1',
|
||||
},
|
||||
})
|
||||
);
|
||||
await removeReactReduxTypesFromPackageJson(tree);
|
||||
|
||||
const packageJson = readJson(tree, '/package.json');
|
||||
expect(packageJson).toMatchObject({
|
||||
dependencies: {},
|
||||
devDependencies: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -4,7 +4,7 @@ import {
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import { JestExecutorOptions } from '@nrwl/jest/src/executors/jest/schema';
|
||||
import type { JestExecutorOptions } from '@nrwl/jest/src/executors/jest/schema';
|
||||
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
import { StringLiteral } from 'typescript';
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
import { addProjectConfiguration, readJson } from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import { installWebpackRollupDependencies } from './install-webpack-rollup-dependencies';
|
||||
|
||||
describe('installWebpackRollupDependencies', () => {
|
||||
it('should install packages if webpack is used', async () => {
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
|
||||
addProjectConfiguration(tree, 'proj', {
|
||||
root: 'proj',
|
||||
targets: {
|
||||
build: { executor: '@nrwl/webpack:webpack' },
|
||||
},
|
||||
});
|
||||
|
||||
await installWebpackRollupDependencies(tree);
|
||||
|
||||
expect(readJson(tree, 'package.json')).toMatchObject({
|
||||
devDependencies: {
|
||||
webpack: '^5.75.0',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should install packages if rollup is used', async () => {
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
|
||||
addProjectConfiguration(tree, 'proj', {
|
||||
root: 'proj',
|
||||
targets: {
|
||||
build: { executor: '@nrwl/rollup:rollup' },
|
||||
},
|
||||
});
|
||||
|
||||
await installWebpackRollupDependencies(tree);
|
||||
|
||||
expect(readJson(tree, 'package.json')).toMatchObject({
|
||||
devDependencies: {
|
||||
webpack: '^5.75.0',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should not install packages if neither webpack nor rollup are used', async () => {
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
|
||||
addProjectConfiguration(tree, 'proj', {
|
||||
root: 'proj',
|
||||
targets: {
|
||||
build: { executor: '@nrwl/vite:vite' },
|
||||
},
|
||||
});
|
||||
|
||||
await installWebpackRollupDependencies(tree);
|
||||
|
||||
expect(readJson(tree, 'package.json')).not.toMatchObject({
|
||||
devDependencies: {
|
||||
webpack: '^5.75.0',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,42 @@
|
||||
import { addDependenciesToPackageJson, getProjects, Tree } from '@nrwl/devkit';
|
||||
|
||||
export function installWebpackRollupDependencies(tree: Tree) {
|
||||
const projects = getProjects(tree);
|
||||
let shouldInstall = false;
|
||||
|
||||
for (const [, project] of projects) {
|
||||
if (
|
||||
project.targets?.build?.executor === '@nrwl/webpack:webpack' ||
|
||||
project.targets?.build?.executor === '@nrwl/rollup:rollup' ||
|
||||
project.targets?.build?.executor === '@nrwl/web:rollup'
|
||||
) {
|
||||
shouldInstall = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldInstall) {
|
||||
// These were previously dependencies of `@nrwl/react` but we've removed them
|
||||
// to accommodate different bundlers and test runners.
|
||||
return addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'@babel/preset-react': '^7.14.5',
|
||||
'@pmmmwh/react-refresh-webpack-plugin': '^0.5.7',
|
||||
'@phenomnomnominal/tsquery': '4.1.1',
|
||||
'@svgr/webpack': '^6.1.2',
|
||||
'css-loader': '^6.4.0',
|
||||
'react-refresh': '^0.10.0',
|
||||
'style-loader': '^3.3.0',
|
||||
stylus: '^0.55.0',
|
||||
'stylus-loader': '^7.1.0',
|
||||
'url-loader': '^4.1.1',
|
||||
webpack: '^5.75.0',
|
||||
'webpack-merge': '^5.8.0',
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default installWebpackRollupDependencies;
|
||||
@ -1,19 +0,0 @@
|
||||
import { Rule, Tree } from '@angular-devkit/schematics';
|
||||
|
||||
export function initRootBabelConfig(): Rule {
|
||||
return (host: Tree) => {
|
||||
if (host.exists('/babel.config.json') || host.exists('/babel.config.js'))
|
||||
return;
|
||||
host.create(
|
||||
'/babel.config.json',
|
||||
JSON.stringify(
|
||||
{
|
||||
presets: ['@nrwl/web/babel'],
|
||||
babelrcRoots: ['*'], // Make sure .babelrc files other than root can be loaded in a monorepo
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
@ -1,110 +0,0 @@
|
||||
import { join } from 'path';
|
||||
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||
import { Rule, Tree } from '@angular-devkit/schematics';
|
||||
import { updateWorkspace } from '@nrwl/workspace/src/utils/workspace';
|
||||
import { readJsonInTree } from '@nrwl/workspace';
|
||||
import { names } from '@nrwl/devkit';
|
||||
|
||||
const testRunner = new SchematicTestRunner(
|
||||
'@nrwl/react',
|
||||
join(__dirname, '../../../generators.json')
|
||||
);
|
||||
|
||||
testRunner.registerCollection(
|
||||
'@nrwl/jest',
|
||||
join(__dirname, '../../../../jest/generators.json')
|
||||
);
|
||||
|
||||
testRunner.registerCollection(
|
||||
'@nrwl/cypress',
|
||||
join(__dirname, '../../../../cypress/generators.json')
|
||||
);
|
||||
|
||||
testRunner.registerCollection(
|
||||
'@nrwl/storybook',
|
||||
join(__dirname, '../../../../storybook/generators.json')
|
||||
);
|
||||
|
||||
export function callRule(rule: Rule, tree: Tree) {
|
||||
return testRunner.callRule(rule, tree).toPromise();
|
||||
}
|
||||
|
||||
export function updateNxJson(tree, update: (json: any) => any) {
|
||||
const updated = update(readJsonInTree(tree, '/nx.json'));
|
||||
tree.overwrite('/nx.json', JSON.stringify(updated));
|
||||
}
|
||||
|
||||
export function createApp(tree: Tree, appName: string): Promise<Tree> {
|
||||
const { fileName } = names(appName);
|
||||
|
||||
tree.create(
|
||||
`/apps/${fileName}/src/main.tsx`,
|
||||
`import ReactDOM from 'react-dom';\n`
|
||||
);
|
||||
|
||||
updateNxJson(tree, (json) => {
|
||||
json.projects[appName] = { tags: [] };
|
||||
return json;
|
||||
});
|
||||
|
||||
return callRule(
|
||||
updateWorkspace((workspace) => {
|
||||
workspace.projects.add({
|
||||
name: fileName,
|
||||
root: `apps/${fileName}`,
|
||||
projectType: 'application',
|
||||
sourceRoot: `apps/${fileName}/src`,
|
||||
targets: {},
|
||||
});
|
||||
}),
|
||||
tree
|
||||
);
|
||||
}
|
||||
|
||||
export function createWebApp(tree: Tree, appName: string): Promise<Tree> {
|
||||
const { fileName } = names(appName);
|
||||
|
||||
tree.create(`/apps/${fileName}/src/index.ts`, `\n`);
|
||||
|
||||
updateNxJson(tree, (json) => {
|
||||
json.projects[appName] = { tags: [] };
|
||||
return json;
|
||||
});
|
||||
|
||||
return callRule(
|
||||
updateWorkspace((workspace) => {
|
||||
workspace.projects.add({
|
||||
name: fileName,
|
||||
root: `apps/${fileName}`,
|
||||
projectType: 'application',
|
||||
sourceRoot: `apps/${fileName}/src`,
|
||||
targets: {},
|
||||
});
|
||||
}),
|
||||
tree
|
||||
);
|
||||
}
|
||||
|
||||
export function createLib(tree: Tree, libName: string): Promise<Tree> {
|
||||
const { fileName } = names(libName);
|
||||
|
||||
tree.create(`/libs/${fileName}/src/index.ts`, `import React from 'react';\n`);
|
||||
|
||||
updateNxJson(tree, (json) => {
|
||||
json.projects[libName] = { tags: [] };
|
||||
return json;
|
||||
});
|
||||
|
||||
return callRule(
|
||||
updateWorkspace((workspace) => {
|
||||
workspace.projects.add({
|
||||
name: fileName,
|
||||
root: `libs/${fileName}`,
|
||||
projectType: 'library',
|
||||
sourceRoot: `libs/${fileName}/src`,
|
||||
targets: {},
|
||||
});
|
||||
}),
|
||||
tree
|
||||
);
|
||||
}
|
||||
@ -3,12 +3,16 @@ export const nxVersion = require('../../package.json').version;
|
||||
export const reactVersion = '18.2.0';
|
||||
export const reactDomVersion = '18.2.0';
|
||||
export const reactIsVersion = '18.2.0';
|
||||
export const swcLoaderVersion = '0.1.15';
|
||||
export const swcCoreVersion = '^1.2.173';
|
||||
export const typesReactVersion = '18.0.25';
|
||||
export const typesReactDomVersion = '18.0.9';
|
||||
export const typesReactIsVersion = '17.0.3';
|
||||
|
||||
export const typesNodeVersion = '18.11.9';
|
||||
|
||||
export const babelPresetReactVersion = '^7.14.5';
|
||||
|
||||
export const styledComponentsVersion = '5.3.6';
|
||||
export const typesStyledComponentsVersion = '5.1.26';
|
||||
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
export * from './src/generators/init/init';
|
||||
export * from './src/generators/rollup-project/rollup-project';
|
||||
export * from './src/executors/rollup/schema';
|
||||
export * from './src/executors/rollup/rollup.impl';
|
||||
|
||||
@ -27,9 +27,7 @@ export async function rollupInitGenerator(tree: Tree, schema: Schema) {
|
||||
'swc-loader': swcLoaderVersion,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (schema.compiler === 'tsc') {
|
||||
} else {
|
||||
task = addDependenciesToPackageJson(tree, {}, { tslib: tsLibVersion });
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export * from './src/utils/config';
|
||||
export * from './src/generators/init/init';
|
||||
export * from './src/generators/webpack-project/webpack-project';
|
||||
export type { WebDevServerOptions } from './src/executors/dev-server/schema';
|
||||
export * from './src/executors/dev-server/dev-server.impl';
|
||||
|
||||
@ -5,10 +5,10 @@ import {
|
||||
runExecutor,
|
||||
} from '@nrwl/devkit';
|
||||
import * as chalk from 'chalk';
|
||||
import { combineAsyncIterableIterators } from '@nrwl/js/src/utils/async-iterable/combine-async-iteratable-iterators';
|
||||
import { combineAsyncIterableIterators } from '@nrwl/devkit/src/utils/async-iterable';
|
||||
|
||||
import { WebpackExecutorOptions } from '../webpack/schema';
|
||||
import { WebSsrDevServerOptions } from './schema';
|
||||
import { TargetOptions, WebSsrDevServerOptions } from './schema';
|
||||
import { waitUntilServerIsListening } from './lib/wait-until-server-is-listening';
|
||||
|
||||
export async function* ssrDevServerExecutor(
|
||||
@ -29,6 +29,7 @@ export async function* ssrDevServerExecutor(
|
||||
const runBrowser = await runExecutor<{
|
||||
success: boolean;
|
||||
baseUrl?: string;
|
||||
options: TargetOptions;
|
||||
}>(
|
||||
browserTarget,
|
||||
{ ...browserOptions, ...options.browserTargetOptions },
|
||||
@ -37,6 +38,7 @@ export async function* ssrDevServerExecutor(
|
||||
const runServer = await runExecutor<{
|
||||
success: boolean;
|
||||
baseUrl?: string;
|
||||
options: TargetOptions;
|
||||
}>(
|
||||
serverTarget,
|
||||
{ ...serverOptions, ...options.serverTargetOptions },
|
||||
|
||||
@ -5,24 +5,31 @@ import {
|
||||
GeneratorCallback,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import { Schema } from './schema';
|
||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
||||
|
||||
import { Schema } from './schema';
|
||||
import {
|
||||
reactRefreshVersion,
|
||||
reactRefreshWebpackPluginVersion,
|
||||
svgrWebpackVersion,
|
||||
swcHelpersVersion,
|
||||
swcLoaderVersion,
|
||||
tsLibVersion,
|
||||
tsQueryVersion,
|
||||
urlLoaderVersion,
|
||||
} from '../../utils/versions';
|
||||
import { addBabelInputs } from '@nrwl/js/src/utils/add-babel-inputs';
|
||||
|
||||
export async function webpackInitGenerator(tree: Tree, schema: Schema) {
|
||||
let task: GeneratorCallback;
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
if (schema.compiler === 'babel') {
|
||||
addBabelInputs(tree);
|
||||
}
|
||||
|
||||
if (schema.compiler === 'swc') {
|
||||
task = addDependenciesToPackageJson(
|
||||
const swcInstallTask = addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
@ -31,17 +38,39 @@ export async function webpackInitGenerator(tree: Tree, schema: Schema) {
|
||||
'swc-loader': swcLoaderVersion,
|
||||
}
|
||||
);
|
||||
tasks.push(swcInstallTask);
|
||||
}
|
||||
|
||||
if (schema.compiler === 'tsc') {
|
||||
task = addDependenciesToPackageJson(tree, {}, { tslib: tsLibVersion });
|
||||
const tscInstallTask = addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{ tslib: tsLibVersion }
|
||||
);
|
||||
tasks.push(tscInstallTask);
|
||||
}
|
||||
|
||||
if (schema.uiFramework === 'react') {
|
||||
const reactInstallTask = addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'@pmmmwh/react-refresh-webpack-plugin':
|
||||
reactRefreshWebpackPluginVersion,
|
||||
'@phenomnomnominal/tsquery': tsQueryVersion,
|
||||
'@svgr/webpack': svgrWebpackVersion,
|
||||
'react-refresh': reactRefreshVersion,
|
||||
'url-loader': urlLoaderVersion,
|
||||
}
|
||||
);
|
||||
tasks.push(reactInstallTask);
|
||||
}
|
||||
|
||||
if (!schema.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return task;
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export default webpackInitGenerator;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export interface Schema {
|
||||
compiler?: 'babel' | 'swc' | 'tsc';
|
||||
uiFramework?: 'react' | 'none';
|
||||
skipFormat?: boolean;
|
||||
}
|
||||
|
||||
@ -6,6 +6,12 @@
|
||||
"description": "Init Webpack Plugin.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"uiFramework": {
|
||||
"type": "string",
|
||||
"description": "UI Framework to use for Vite.",
|
||||
"enum": ["react", "none"],
|
||||
"x-prompt": "What UI framework plugin should Webpack use?"
|
||||
},
|
||||
"compiler": {
|
||||
"type": "string",
|
||||
"enum": ["babel", "swc", "tsc"],
|
||||
|
||||
@ -3,3 +3,10 @@ export const nxVersion = require('../../package.json').version;
|
||||
export const swcLoaderVersion = '0.1.15';
|
||||
export const swcHelpersVersion = '~0.4.11';
|
||||
export const tsLibVersion = '^2.3.0';
|
||||
|
||||
// React apps
|
||||
export const reactRefreshWebpackPluginVersion = '^0.5.7';
|
||||
export const tsQueryVersion = '4.1.1';
|
||||
export const svgrWebpackVersion = '^6.1.2';
|
||||
export const reactRefreshVersion = '^0.10.0';
|
||||
export const urlLoaderVersion = '^4.1.1';
|
||||
|
||||
@ -109,9 +109,6 @@
|
||||
{
|
||||
"command": "node ./scripts/add-dependency-to-build.js workspace @nrwl/devkit"
|
||||
},
|
||||
{
|
||||
"command": "node ./scripts/add-dependency-to-build.js workspace @nrwl/jest"
|
||||
},
|
||||
{
|
||||
"command": "node ./scripts/add-dependency-to-build.js workspace @nrwl/linter"
|
||||
}
|
||||
|
||||
@ -1,19 +1,20 @@
|
||||
import {
|
||||
Tree,
|
||||
addDependenciesToPackageJson,
|
||||
addProjectConfiguration,
|
||||
convertNxGenerator,
|
||||
ensurePackage,
|
||||
extractLayoutDirectory,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
GeneratorCallback,
|
||||
getWorkspaceLayout,
|
||||
joinPathFragments,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
generateFiles,
|
||||
toJS,
|
||||
getWorkspaceLayout,
|
||||
addProjectConfiguration,
|
||||
formatFiles,
|
||||
updateJson,
|
||||
GeneratorCallback,
|
||||
joinPathFragments,
|
||||
ProjectConfiguration,
|
||||
addDependenciesToPackageJson,
|
||||
extractLayoutDirectory,
|
||||
toJS,
|
||||
Tree,
|
||||
updateJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { getImportPath } from 'nx/src/utils/path';
|
||||
import { join } from 'path';
|
||||
@ -25,11 +26,6 @@ import {
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { Schema } from './schema';
|
||||
|
||||
// nx-ignore-next-line
|
||||
const { jestProjectGenerator } = require('@nrwl/jest');
|
||||
// nx-ignore-next-line
|
||||
const { lintProjectGenerator, Linter } = require('@nrwl/linter');
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
fileName: string;
|
||||
@ -74,10 +70,12 @@ function addProject(tree: Tree, options: NormalizedSchema) {
|
||||
);
|
||||
}
|
||||
|
||||
export function addLint(
|
||||
export async function addLint(
|
||||
tree: Tree,
|
||||
options: NormalizedSchema
|
||||
): Promise<GeneratorCallback> {
|
||||
await ensurePackage(tree, '@nrwl/linter', nxVersion);
|
||||
const { lintProjectGenerator } = require('@nrwl/linter');
|
||||
return lintProjectGenerator(tree, {
|
||||
project: options.name,
|
||||
linter: options.linter,
|
||||
@ -178,6 +176,8 @@ async function addJest(
|
||||
tree: Tree,
|
||||
options: NormalizedSchema
|
||||
): Promise<GeneratorCallback> {
|
||||
await ensurePackage(tree, '@nrwl/jest', nxVersion);
|
||||
const { jestProjectGenerator } = require('@nrwl/jest');
|
||||
return await jestProjectGenerator(tree, {
|
||||
...options,
|
||||
project: options.name,
|
||||
@ -232,7 +232,7 @@ function normalizeOptions(tree: Tree, options: Schema): NormalizedSchema {
|
||||
}
|
||||
|
||||
if (!options.linter) {
|
||||
options.linter = Linter.EsLint;
|
||||
options.linter = 'eslint';
|
||||
}
|
||||
|
||||
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
|
||||
@ -3,7 +3,21 @@ import { join } from 'path';
|
||||
|
||||
// Ignore packages that are defined here per package
|
||||
const IGNORE_MATCHES_IN_PACKAGE = {
|
||||
'*': ['nx', '@nrwl/cli', '@nrwl/workspace', 'prettier', 'typescript', 'rxjs'],
|
||||
'*': [
|
||||
'nx',
|
||||
'prettier',
|
||||
'typescript',
|
||||
'rxjs',
|
||||
'@nrwl/cli',
|
||||
'@nrwl/workspace',
|
||||
// These are installed as needed and should not be added to package.json
|
||||
'@nrwl/cypress',
|
||||
'@nrwl/jest',
|
||||
'@nrwl/rollup',
|
||||
'@nrwl/storybook',
|
||||
'@nrwl/vite',
|
||||
'@nrwl/webpack',
|
||||
],
|
||||
angular: [
|
||||
'@angular-devkit/architect',
|
||||
'@angular-devkit/build-angular',
|
||||
@ -68,26 +82,30 @@ const IGNORE_MATCHES_IN_PACKAGE = {
|
||||
'webpack',
|
||||
],
|
||||
react: [
|
||||
'babel-plugin-emotion',
|
||||
'babel-plugin-styled-components',
|
||||
'rollup',
|
||||
'webpack',
|
||||
// These are brought in by the webpack, rollup, or vite packages via init generators.
|
||||
'@babel/preset-react',
|
||||
'@module-federation/node',
|
||||
'@phenomnomnominal/tsquery',
|
||||
'@pmmmwh/react-refresh-webpack-plugin',
|
||||
'@svgr/webpack',
|
||||
'@swc/jest',
|
||||
'babel-jest',
|
||||
'@angular-devkit/core',
|
||||
'@angular-devkit/schematics',
|
||||
// TODO(caleb): remove when refactoring plugin to use @nrwl/web
|
||||
// webpack plugins for cypress component testing dev server
|
||||
'babel-loader',
|
||||
'babel-plugin-emotion',
|
||||
'babel-plugin-styled-components',
|
||||
'css-loader',
|
||||
'less-loader',
|
||||
'react-refresh',
|
||||
'rollup',
|
||||
'sass',
|
||||
'sass-loader',
|
||||
'style-loader',
|
||||
'stylus-loader',
|
||||
'swc-loader',
|
||||
'tsconfig-paths-webpack-plugin',
|
||||
'@module-federation/node',
|
||||
'url-loader',
|
||||
'webpack',
|
||||
'webpack-merge',
|
||||
],
|
||||
rollup: ['@swc/core'],
|
||||
storybook: [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user