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)
|
- [defaultTasksRunner](../../devkit/index#defaulttasksrunner)
|
||||||
- [detectPackageManager](../../devkit/index#detectpackagemanager)
|
- [detectPackageManager](../../devkit/index#detectpackagemanager)
|
||||||
- [detectWorkspaceScope](../../devkit/index#detectworkspacescope)
|
- [detectWorkspaceScope](../../devkit/index#detectworkspacescope)
|
||||||
|
- [ensurePackage](../../devkit/index#ensurepackage)
|
||||||
- [extractLayoutDirectory](../../devkit/index#extractlayoutdirectory)
|
- [extractLayoutDirectory](../../devkit/index#extractlayoutdirectory)
|
||||||
- [formatFiles](../../devkit/index#formatfiles)
|
- [formatFiles](../../devkit/index#formatfiles)
|
||||||
- [generateFiles](../../devkit/index#generatefiles)
|
- [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
|
||||||
|
|
||||||
▸ **extractLayoutDirectory**(`directory`): `Object`
|
▸ **extractLayoutDirectory**(`directory`): `Object`
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -18,6 +18,12 @@
|
|||||||
"description": "Init Webpack Plugin.",
|
"description": "Init Webpack Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"uiFramework": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "UI Framework to use for Vite.",
|
||||||
|
"enum": ["react", "none"],
|
||||||
|
"x-prompt": "What UI framework plugin should Webpack use?"
|
||||||
|
},
|
||||||
"compiler": {
|
"compiler": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["babel", "swc", "tsc"],
|
"enum": ["babel", "swc", "tsc"],
|
||||||
|
|||||||
@ -225,6 +225,7 @@ export { readJsonFile, writeJsonFile } from 'nx/src/utils/fileutils';
|
|||||||
*/
|
*/
|
||||||
export {
|
export {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
|
ensurePackage,
|
||||||
removeDependenciesFromPackageJson,
|
removeDependenciesFromPackageJson,
|
||||||
} from './src/utils/package-json';
|
} from './src/utils/package-json';
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export async function* combineAsyncIterableIterators(
|
export async function* combineAsyncIterableIterators<T = any>(
|
||||||
...iterators: { 0: AsyncIterableIterator<any> } & AsyncIterableIterator<any>[]
|
...iterators: { 0: AsyncIterableIterator<T> } & AsyncIterableIterator<T>[]
|
||||||
) {
|
): AsyncGenerator<T> {
|
||||||
let [options] = iterators;
|
let [options] = iterators;
|
||||||
if (typeof options.next === 'function') {
|
if (typeof options.next === 'function') {
|
||||||
options = Object.create(null);
|
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,
|
index?: number,
|
||||||
data?: AsyncIterable<T> | AsyncIterableIterator<T>
|
data?: AsyncIterable<T> | AsyncIterableIterator<T>
|
||||||
) => O
|
) => O
|
||||||
) {
|
): AsyncIterable<O> | AsyncIterableIterator<O> {
|
||||||
async function* f() {
|
async function* f() {
|
||||||
const generator = data[Symbol.asyncIterator] || data[Symbol.iterator];
|
const generator = data[Symbol.asyncIterator] || data[Symbol.iterator];
|
||||||
const iterator = generator.call(data);
|
const iterator = generator.call(data);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { tapAsyncIterator } from './tap-async-iteratable';
|
import { tapAsyncIterable } from './tap-async-iteratable';
|
||||||
|
|
||||||
describe('tapAsyncIterator', () => {
|
describe('tapAsyncIterator', () => {
|
||||||
it('should tap values', async () => {
|
it('should tap values', async () => {
|
||||||
@ -11,7 +11,7 @@ describe('tapAsyncIterator', () => {
|
|||||||
const tapped = [];
|
const tapped = [];
|
||||||
const results = [];
|
const results = [];
|
||||||
|
|
||||||
const c = tapAsyncIterator(f(), (x) => {
|
const c = tapAsyncIterable(f(), (x) => {
|
||||||
tapped.push(`tap: ${x}`);
|
tapped.push(`tap: ${x}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { mapAsyncIterable } from './map-async-iteratable';
|
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>,
|
data: AsyncIterable<T> | AsyncIterableIterator<T>,
|
||||||
fn: (input: I) => void
|
fn: (input: I) => void
|
||||||
) {
|
): AsyncIterable<T> | AsyncIterableIterator<T> {
|
||||||
return yield* mapAsyncIterable(data, (x) => {
|
return yield* mapAsyncIterable(data, (x) => {
|
||||||
fn(x);
|
fn(x);
|
||||||
return x;
|
return x;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import type { Tree } from 'nx/src/generators/tree';
|
import type { Tree } from 'nx/src/generators/tree';
|
||||||
import { readJson, writeJson } from 'nx/src/generators/utils/json';
|
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';
|
import { createTree } from 'nx/src/generators/testing-utils/create-tree';
|
||||||
|
|
||||||
describe('addDependenciesToPackageJson', () => {
|
describe('addDependenciesToPackageJson', () => {
|
||||||
@ -310,3 +310,42 @@ describe('addDependenciesToPackageJson', () => {
|
|||||||
expect(installTask).toBeDefined();
|
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 { installPackagesTask } from '../tasks/install-packages-task';
|
||||||
import type { Tree } from 'nx/src/generators/tree';
|
import type { Tree } from 'nx/src/generators/tree';
|
||||||
import { GeneratorCallback } from 'nx/src/config/misc-interfaces';
|
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 = {
|
const NON_SEMVER_TAGS = {
|
||||||
'*': 2,
|
'*': 2,
|
||||||
@ -274,3 +276,73 @@ function requiresRemovingOfPackages(
|
|||||||
|
|
||||||
return needsDepsUpdate || needsDevDepsUpdate;
|
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 { EsBuildExecutorOptions } from './schema';
|
||||||
import { removeSync, writeJsonSync } from 'fs-extra';
|
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 { buildEsbuildOptions } from './lib/build-esbuild-options';
|
||||||
import { getExtraDependencies } from './lib/get-extra-dependencies';
|
import { getExtraDependencies } from './lib/get-extra-dependencies';
|
||||||
import { DependentBuildableProjectNode } from '@nrwl/workspace/src/utilities/buildable-libs-utils';
|
import { DependentBuildableProjectNode } from '@nrwl/workspace/src/utilities/buildable-libs-utils';
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
"builders": "./executors.json",
|
"builders": "./executors.json",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nrwl/devkit": "file:../devkit",
|
"@nrwl/devkit": "file:../devkit",
|
||||||
"@nrwl/jest": "file:../jest",
|
|
||||||
"@nrwl/linter": "file:../linter",
|
"@nrwl/linter": "file:../linter",
|
||||||
"@nrwl/workspace": "file:../workspace",
|
"@nrwl/workspace": "file:../workspace",
|
||||||
"chalk": "4.1.0",
|
"chalk": "4.1.0",
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import {
|
|||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
|
ensurePackage,
|
||||||
extractLayoutDirectory,
|
extractLayoutDirectory,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
@ -18,7 +19,6 @@ import {
|
|||||||
writeJson,
|
writeJson,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { getImportPath } from 'nx/src/utils/path';
|
import { getImportPath } from 'nx/src/utils/path';
|
||||||
import { jestProjectGenerator } from '@nrwl/jest';
|
|
||||||
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
||||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
import {
|
import {
|
||||||
@ -293,6 +293,8 @@ async function addJest(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: NormalizedSchema
|
options: NormalizedSchema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
|
await ensurePackage(tree, '@nrwl/jest', nxVersion);
|
||||||
|
const { jestProjectGenerator } = await import('@nrwl/jest');
|
||||||
return await jestProjectGenerator(tree, {
|
return await jestProjectGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
project: options.name,
|
project: options.name,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { cacheDir, ExecutorContext, logger } from '@nrwl/devkit';
|
import { cacheDir, ExecutorContext, logger } from '@nrwl/devkit';
|
||||||
import { exec, execSync } from 'child_process';
|
import { exec, execSync } from 'child_process';
|
||||||
import { removeSync } from 'fs-extra';
|
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 { NormalizedSwcExecutorOptions, SwcCliOptions } from '../schema';
|
||||||
import { printDiagnostics } from '../typescript/print-diagnostics';
|
import { printDiagnostics } from '../typescript/print-diagnostics';
|
||||||
import { runTypeCheck, TypeCheckOptions } from '../typescript/run-type-check';
|
import { runTypeCheck, TypeCheckOptions } from '../typescript/run-type-check';
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {
|
|||||||
TypeScriptCompilationOptions,
|
TypeScriptCompilationOptions,
|
||||||
} from '@nrwl/workspace/src/utilities/typescript/compilation';
|
} from '@nrwl/workspace/src/utilities/typescript/compilation';
|
||||||
import type { Diagnostic } from 'typescript';
|
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';
|
import { NormalizedExecutorOptions } from '../schema';
|
||||||
|
|
||||||
const TYPESCRIPT_FOUND_N_ERRORS_WATCHING_FOR_FILE_CHANGES = 6194;
|
const TYPESCRIPT_FOUND_N_ERRORS_WATCHING_FOR_FILE_CHANGES = 6194;
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nrwl/devkit": "file:../devkit",
|
"@nrwl/devkit": "file:../devkit",
|
||||||
"@nrwl/jest": "file:../jest",
|
|
||||||
"@phenomnomnominal/tsquery": "4.1.1",
|
"@phenomnomnominal/tsquery": "4.1.1",
|
||||||
"nx": "file:../nx",
|
"nx": "file:../nx",
|
||||||
"tmp": "~0.2.1",
|
"tmp": "~0.2.1",
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import {
|
|||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
|
ensurePackage,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
@ -11,17 +12,22 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateWorkspaceConfiguration,
|
updateWorkspaceConfiguration,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { addPropertyToJestConfig, jestProjectGenerator } from '@nrwl/jest';
|
|
||||||
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { workspaceLintPluginDir } from '../../utils/workspace-lint-rules';
|
import { workspaceLintPluginDir } from '../../utils/workspace-lint-rules';
|
||||||
import { swcCoreVersion, swcNodeVersion } from 'nx/src/utils/versions';
|
import { swcCoreVersion, swcNodeVersion } from 'nx/src/utils/versions';
|
||||||
|
import { nxVersion } from '../../utils/versions';
|
||||||
|
|
||||||
export const WORKSPACE_RULES_PROJECT_NAME = 'eslint-rules';
|
export const WORKSPACE_RULES_PROJECT_NAME = 'eslint-rules';
|
||||||
|
|
||||||
export const WORKSPACE_PLUGIN_DIR = 'tools/eslint-rules';
|
export const WORKSPACE_PLUGIN_DIR = 'tools/eslint-rules';
|
||||||
|
|
||||||
export async function lintWorkspaceRulesProjectGenerator(tree: Tree) {
|
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
|
// Noop if the workspace rules project already exists
|
||||||
try {
|
try {
|
||||||
readProjectConfiguration(tree, WORKSPACE_RULES_PROJECT_NAME);
|
readProjectConfiguration(tree, WORKSPACE_RULES_PROJECT_NAME);
|
||||||
|
|||||||
@ -4,11 +4,11 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
visitNotIgnoredFiles,
|
visitNotIgnoredFiles,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { addPropertyToJestConfig } from '@nrwl/jest';
|
|
||||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||||
|
|
||||||
export default async function eslint8Updates(tree: Tree) {
|
export default async function eslint8Updates(tree: Tree) {
|
||||||
try {
|
try {
|
||||||
|
const { addPropertyToJestConfig } = await import('@nrwl/jest');
|
||||||
const existingJestConfigPath = normalizePath(
|
const existingJestConfigPath = normalizePath(
|
||||||
'tools/eslint-rules/jest.config.js'
|
'tools/eslint-rules/jest.config.js'
|
||||||
);
|
);
|
||||||
|
|||||||
@ -9,11 +9,12 @@ import {
|
|||||||
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
||||||
import { exampleRootTslintJson } from '@nrwl/linter';
|
import { exampleRootTslintJson } from '@nrwl/linter';
|
||||||
import { conversionGenerator } from './convert-tslint-to-eslint';
|
import { conversionGenerator } from './convert-tslint-to-eslint';
|
||||||
|
import * as devkit from '@nrwl/devkit';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Don't run actual child_process implementation of installPackagesTask()
|
* Don't run actual child_process implementation of installPackagesTask()
|
||||||
*/
|
*/
|
||||||
jest.mock('child_process');
|
// jest.mock('child_process');
|
||||||
|
|
||||||
const appProjectName = 'nest-app-1';
|
const appProjectName = 'nest-app-1';
|
||||||
const appProjectRoot = `apps/${appProjectName}`;
|
const appProjectRoot = `apps/${appProjectName}`;
|
||||||
@ -101,6 +102,7 @@ describe('convert-tslint-to-eslint', () => {
|
|||||||
let host: Tree;
|
let host: Tree;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
jest.spyOn(devkit, 'installPackagesTask');
|
||||||
host = createTreeWithEmptyV1Workspace();
|
host = createTreeWithEmptyV1Workspace();
|
||||||
|
|
||||||
writeJson(host, 'tslint.json', exampleRootTslintJson.raw);
|
writeJson(host, 'tslint.json', exampleRootTslintJson.raw);
|
||||||
|
|||||||
@ -289,6 +289,9 @@ export async function generate(cwd: string, args: { [k: string]: any }) {
|
|||||||
'generate',
|
'generate',
|
||||||
projectsConfiguration
|
projectsConfiguration
|
||||||
);
|
);
|
||||||
|
if (opts.dryRun) {
|
||||||
|
process.env.NX_DRY_RUN = 'true';
|
||||||
|
}
|
||||||
const { normalizedGeneratorName, schema, implementationFactory, aliases } =
|
const { normalizedGeneratorName, schema, implementationFactory, aliases } =
|
||||||
ws.readGenerator(opts.collectionName, opts.generatorName);
|
ws.readGenerator(opts.collectionName, opts.generatorName);
|
||||||
|
|
||||||
|
|||||||
@ -22,8 +22,8 @@ export async function createAllStories(
|
|||||||
const projects = getProjects(tree);
|
const projects = getProjects(tree);
|
||||||
const projectConfiguration = projects.get(projectName);
|
const projectConfiguration = projects.get(projectName);
|
||||||
|
|
||||||
const { sourceRoot, root } = projectConfiguration;
|
const { sourceRoot } = projectConfiguration;
|
||||||
const projectPath = projectRootPath(projectConfiguration);
|
const projectPath = await projectRootPath(tree, projectConfiguration);
|
||||||
|
|
||||||
let componentPaths: string[] = [];
|
let componentPaths: string[] = [];
|
||||||
visitNotIgnoredFiles(tree, projectPath, (path) => {
|
visitNotIgnoredFiles(tree, projectPath, (path) => {
|
||||||
|
|||||||
@ -71,6 +71,12 @@
|
|||||||
"version": "15.3.0-beta.0",
|
"version": "15.3.0-beta.0",
|
||||||
"description": "Update projects using @nrwl/web:rollup to @nrwl/rollup:rollup for build.",
|
"description": "Update projects using @nrwl/web:rollup to @nrwl/rollup:rollup for build.",
|
||||||
"factory": "./src/migrations/update-15-3-0/update-rollup-executor"
|
"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": {
|
"packageJsonUpdates": {
|
||||||
|
|||||||
@ -31,32 +31,12 @@
|
|||||||
"migrations": "./migrations.json"
|
"migrations": "./migrations.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.15.0",
|
|
||||||
"@babel/preset-react": "^7.14.5",
|
|
||||||
"@nrwl/cypress": "file:../cypress",
|
|
||||||
"@nrwl/devkit": "file:../devkit",
|
"@nrwl/devkit": "file:../devkit",
|
||||||
"@nrwl/jest": "file:../jest",
|
|
||||||
"@nrwl/js": "file:../js",
|
|
||||||
"@nrwl/linter": "file:../linter",
|
"@nrwl/linter": "file:../linter",
|
||||||
"@nrwl/storybook": "file:../storybook",
|
|
||||||
"@nrwl/vite": "file:../vite",
|
|
||||||
"@nrwl/web": "file:../web",
|
|
||||||
"@nrwl/webpack": "file:../webpack",
|
|
||||||
"@nrwl/workspace": "file:../workspace",
|
"@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",
|
"chalk": "4.1.0",
|
||||||
"css-loader": "^6.4.0",
|
|
||||||
"minimatch": "3.0.5",
|
"minimatch": "3.0.5",
|
||||||
"react-refresh": "^0.10.0",
|
"semver": "7.3.4"
|
||||||
"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"
|
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"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 { WebDevServerOptions } from '@nrwl/webpack/src/executors/dev-server/schema';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import * as chalk from 'chalk';
|
import * as chalk from 'chalk';
|
||||||
import { combineAsyncIterableIterators } from '@nrwl/js/src/utils/async-iterable/combine-async-iteratable-iterators';
|
import {
|
||||||
import { tapAsyncIterator } from '@nrwl/js/src/utils/async-iterable/tap-async-iteratable';
|
combineAsyncIterableIterators,
|
||||||
|
tapAsyncIterable,
|
||||||
|
} from '@nrwl/devkit/src/utils/async-iterable';
|
||||||
|
|
||||||
type ModuleFederationDevServerOptions = WebDevServerOptions & {
|
type ModuleFederationDevServerOptions = WebDevServerOptions & {
|
||||||
devRemotes?: string | string[];
|
devRemotes?: string | string[];
|
||||||
@ -65,7 +67,7 @@ export default async function* moduleFederationDevServer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let numAwaiting = knownRemotes.length + 1; // remotes + host
|
let numAwaiting = knownRemotes.length + 1; // remotes + host
|
||||||
return yield* tapAsyncIterator(iter, (x) => {
|
return yield* tapAsyncIterable(iter, (x) => {
|
||||||
numAwaiting--;
|
numAwaiting--;
|
||||||
if (numAwaiting === 0) {
|
if (numAwaiting === 0) {
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { addStyledModuleDependencies } from '../../rules/add-styled-dependencies
|
|||||||
import {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
|
ensurePackage,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
@ -24,10 +25,12 @@ import {
|
|||||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
import reactInitGenerator from '../init/init';
|
import reactInitGenerator from '../init/init';
|
||||||
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
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 { mapLintPattern } from '@nrwl/linter/src/generators/lint-project/lint-project';
|
||||||
|
import {
|
||||||
|
nxVersion,
|
||||||
|
swcCoreVersion,
|
||||||
|
swcLoaderVersion,
|
||||||
|
} from '../../utils/versions';
|
||||||
|
|
||||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
@ -90,6 +93,8 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
|||||||
addProject(host, options);
|
addProject(host, options);
|
||||||
|
|
||||||
if (options.bundler === 'vite') {
|
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.
|
// 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
|
// See: https://vitejs.dev/guide/env-and-mode.html
|
||||||
host.delete(joinPathFragments(options.appProjectRoot, 'src/environments'));
|
host.delete(joinPathFragments(options.appProjectRoot, 'src/environments'));
|
||||||
@ -101,9 +106,20 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
|||||||
includeVitest: true,
|
includeVitest: true,
|
||||||
});
|
});
|
||||||
tasks.push(viteTask);
|
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') {
|
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
|
||||||
|
await ensurePackage(host, '@nrwl/vite', nxVersion);
|
||||||
|
const { vitestGenerator } = await import('@nrwl/vite');
|
||||||
|
|
||||||
const vitestTask = await vitestGenerator(host, {
|
const vitestTask = await vitestGenerator(host, {
|
||||||
uiFramework: 'react',
|
uiFramework: 'react',
|
||||||
project: options.projectName,
|
project: options.projectName,
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
import { cypressProjectGenerator } from '@nrwl/cypress';
|
import { ensurePackage, Tree } from '@nrwl/devkit';
|
||||||
import { Tree } from '@nrwl/devkit';
|
import { nxVersion } from '../../../utils/versions';
|
||||||
import { NormalizedSchema } from '../schema';
|
import { NormalizedSchema } from '../schema';
|
||||||
|
|
||||||
export async function addCypress(host: Tree, options: NormalizedSchema) {
|
export async function addCypress(host: Tree, options: NormalizedSchema) {
|
||||||
if (options.e2eTestRunner !== 'cypress') {
|
if (options.e2eTestRunner !== 'cypress') {
|
||||||
return () => {};
|
return () => {};
|
||||||
}
|
}
|
||||||
|
await ensurePackage(host, '@nrwl/cypress', nxVersion);
|
||||||
|
const { cypressProjectGenerator } = await import('@nrwl/cypress');
|
||||||
|
|
||||||
return await cypressProjectGenerator(host, {
|
return await cypressProjectGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { Tree } from '@nrwl/devkit';
|
import { ensurePackage, Tree } from '@nrwl/devkit';
|
||||||
import { jestProjectGenerator } from '@nrwl/jest';
|
|
||||||
import { NormalizedSchema } from '../schema';
|
import { NormalizedSchema } from '../schema';
|
||||||
|
import { nxVersion } from '../../../utils/versions';
|
||||||
|
|
||||||
export async function addJest(host: Tree, options: NormalizedSchema) {
|
export async function addJest(host: Tree, options: NormalizedSchema) {
|
||||||
|
await ensurePackage(host, '@nrwl/jest', nxVersion);
|
||||||
|
const { jestProjectGenerator } = await import('@nrwl/jest');
|
||||||
|
|
||||||
if (options.unitTestRunner !== 'jest') {
|
if (options.unitTestRunner !== 'jest') {
|
||||||
return () => {};
|
return () => {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ describe(componentTestGenerator.name, () => {
|
|||||||
component: true,
|
component: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
componentTestGenerator(tree, {
|
await componentTestGenerator(tree, {
|
||||||
project: 'some-lib',
|
project: 'some-lib',
|
||||||
componentPath: 'lib/some-lib.tsx',
|
componentPath: 'lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -47,7 +47,7 @@ describe(componentTestGenerator.name, () => {
|
|||||||
js: true,
|
js: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
componentTestGenerator(tree, {
|
await componentTestGenerator(tree, {
|
||||||
project: 'some-lib',
|
project: 'some-lib',
|
||||||
componentPath: 'lib/some-lib.js',
|
componentPath: 'lib/some-lib.js',
|
||||||
});
|
});
|
||||||
@ -67,7 +67,7 @@ describe(componentTestGenerator.name, () => {
|
|||||||
component: true,
|
component: true,
|
||||||
});
|
});
|
||||||
tree.write('libs/some-lib/src/lib/some-lib.cy.tsx', 'existing content');
|
tree.write('libs/some-lib/src/lib/some-lib.cy.tsx', 'existing content');
|
||||||
componentTestGenerator(tree, {
|
await componentTestGenerator(tree, {
|
||||||
project: 'some-lib',
|
project: 'some-lib',
|
||||||
componentPath: 'lib/some-lib.tsx',
|
componentPath: 'lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -89,12 +89,12 @@ describe(componentTestGenerator.name, () => {
|
|||||||
component: true,
|
component: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(() => {
|
await expect(
|
||||||
componentTestGenerator(tree, {
|
componentTestGenerator(tree, {
|
||||||
project: 'some-lib',
|
project: 'some-lib',
|
||||||
componentPath: 'lib/blah/abc-123.blah',
|
componentPath: 'lib/blah/abc-123.blah',
|
||||||
});
|
})
|
||||||
}).not.toThrow();
|
).resolves.not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle being provided the full path to the component', async () => {
|
it('should handle being provided the full path to the component', async () => {
|
||||||
@ -109,7 +109,7 @@ describe(componentTestGenerator.name, () => {
|
|||||||
component: true,
|
component: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
componentTestGenerator(tree, {
|
await componentTestGenerator(tree, {
|
||||||
project: 'some-lib',
|
project: 'some-lib',
|
||||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -144,11 +144,11 @@ export interface AnotherCmpProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AnotherCmp(props: 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',
|
project: 'some-lib',
|
||||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -180,7 +180,7 @@ export function AnotherCmp() {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
componentTestGenerator(tree, {
|
await componentTestGenerator(tree, {
|
||||||
project: 'some-lib',
|
project: 'some-lib',
|
||||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -214,7 +214,7 @@ export interface AnotherCmpProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function AnotherCmp(props: AnotherCmpProps) {
|
export default function AnotherCmp(props: AnotherCmpProps) {
|
||||||
return <button onClick="{handleClick}">{props.text}</button>;
|
return <button onClick='{handleClick}'>{props.text}</button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AnotherCmp2() {
|
export function AnotherCmp2() {
|
||||||
@ -222,7 +222,7 @@ export function AnotherCmp2() {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
componentTestGenerator(tree, {
|
await componentTestGenerator(tree, {
|
||||||
project: 'some-lib',
|
project: 'some-lib',
|
||||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -257,7 +257,7 @@ export interface AnotherCmpProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AnotherCmp(props: AnotherCmpProps) {
|
export function AnotherCmp(props: AnotherCmpProps) {
|
||||||
return <button onClick="{handleClick}">{props.text}</button>;
|
return <button onClick='{handleClick}'>{props.text}</button>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AnotherCmp2() {
|
export function AnotherCmp2() {
|
||||||
@ -265,7 +265,7 @@ export function AnotherCmp2() {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
componentTestGenerator(tree, {
|
await componentTestGenerator(tree, {
|
||||||
project: 'some-lib',
|
project: 'some-lib',
|
||||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -302,11 +302,11 @@ export interface AnotherCmpProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AnotherCmp(props: 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',
|
project: 'some-lib',
|
||||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -328,7 +328,7 @@ export function AnotherCmp(props: AnotherCmpProps) {
|
|||||||
unitTestRunner: 'none',
|
unitTestRunner: 'none',
|
||||||
component: true,
|
component: true,
|
||||||
});
|
});
|
||||||
componentTestGenerator(tree, {
|
await componentTestGenerator(tree, {
|
||||||
project: 'some-lib',
|
project: 'some-lib',
|
||||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -362,11 +362,11 @@ export interface AnotherCmpProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function AnotherCmp(props: 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',
|
project: 'some-lib',
|
||||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
@ -400,11 +400,11 @@ export interface AnotherCmpProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AnotherCmp(props: 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',
|
project: 'some-lib',
|
||||||
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
componentPath: 'libs/some-lib/src/lib/some-lib.tsx',
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { assertMinimumCypressVersion } from '@nrwl/cypress/src/utils/cypress-version';
|
|
||||||
import {
|
import {
|
||||||
|
ensurePackage,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
@ -12,12 +12,17 @@ import {
|
|||||||
getComponentNode,
|
getComponentNode,
|
||||||
} from '../../utils/ast-utils';
|
} from '../../utils/ast-utils';
|
||||||
import { getDefaultsForComponent } from '../../utils/component-props';
|
import { getDefaultsForComponent } from '../../utils/component-props';
|
||||||
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { ComponentTestSchema } from './schema';
|
import { ComponentTestSchema } from './schema';
|
||||||
|
|
||||||
export function componentTestGenerator(
|
export async function componentTestGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: ComponentTestSchema
|
options: ComponentTestSchema
|
||||||
) {
|
) {
|
||||||
|
await ensurePackage(tree, '@nrwl/cypress', nxVersion);
|
||||||
|
const { assertMinimumCypressVersion } = await import(
|
||||||
|
'@nrwl/cypress/src/utils/cypress-version'
|
||||||
|
);
|
||||||
assertMinimumCypressVersion(10);
|
assertMinimumCypressVersion(10);
|
||||||
|
|
||||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
import { cypressComponentProject } from '@nrwl/cypress';
|
import {
|
||||||
import { formatFiles, readProjectConfiguration, Tree } from '@nrwl/devkit';
|
ensurePackage,
|
||||||
|
formatFiles,
|
||||||
|
readProjectConfiguration,
|
||||||
|
Tree,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { addFiles } from './lib/add-files';
|
import { addFiles } from './lib/add-files';
|
||||||
import { updateProjectConfig } from './lib/update-configs';
|
import { updateProjectConfig } from './lib/update-configs';
|
||||||
import { CypressComponentConfigurationSchema } from './schema.d';
|
import { CypressComponentConfigurationSchema } from './schema.d';
|
||||||
@ -13,6 +18,8 @@ export async function cypressComponentConfigGenerator(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: CypressComponentConfigurationSchema
|
options: CypressComponentConfigurationSchema
|
||||||
) {
|
) {
|
||||||
|
await ensurePackage(tree, '@nrwl/cypress', nxVersion);
|
||||||
|
const { cypressComponentProject } = await import('@nrwl/cypress');
|
||||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||||
const installTask = await cypressComponentProject(tree, {
|
const installTask = await cypressComponentProject(tree, {
|
||||||
project: options.project,
|
project: options.project,
|
||||||
@ -20,7 +27,7 @@ export async function cypressComponentConfigGenerator(
|
|||||||
});
|
});
|
||||||
|
|
||||||
await updateProjectConfig(tree, options);
|
await updateProjectConfig(tree, options);
|
||||||
addFiles(tree, projectConfig, options);
|
await addFiles(tree, projectConfig, options);
|
||||||
if (options.skipFormat) {
|
if (options.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import { CypressComponentConfigurationSchema } from '../schema';
|
|||||||
const allowedFileExt = new RegExp(/\.[jt]sx?/g);
|
const allowedFileExt = new RegExp(/\.[jt]sx?/g);
|
||||||
const isSpecFile = new RegExp(/(spec|test)\./g);
|
const isSpecFile = new RegExp(/(spec|test)\./g);
|
||||||
|
|
||||||
export function addFiles(
|
export async function addFiles(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
projectConfig: ProjectConfiguration,
|
projectConfig: ProjectConfiguration,
|
||||||
options: CypressComponentConfigurationSchema
|
options: CypressComponentConfigurationSchema
|
||||||
@ -36,14 +36,19 @@ export function addFiles(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (options.generateTests) {
|
if (options.generateTests) {
|
||||||
|
const filePaths = [];
|
||||||
visitNotIgnoredFiles(tree, projectConfig.sourceRoot, (filePath) => {
|
visitNotIgnoredFiles(tree, projectConfig.sourceRoot, (filePath) => {
|
||||||
if (isComponent(tree, filePath)) {
|
if (isComponent(tree, filePath)) {
|
||||||
componentTestGenerator(tree, {
|
filePaths.push(filePath);
|
||||||
project: options.project,
|
|
||||||
componentPath: 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 {
|
import {
|
||||||
joinPathFragments,
|
|
||||||
ProjectConfiguration,
|
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { CypressComponentConfigurationSchema } from '../schema';
|
import { CypressComponentConfigurationSchema } from '../schema';
|
||||||
@ -13,6 +9,9 @@ export async function updateProjectConfig(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: CypressComponentConfigurationSchema
|
options: CypressComponentConfigurationSchema
|
||||||
) {
|
) {
|
||||||
|
const { findBuildConfig } = await import(
|
||||||
|
'@nrwl/cypress/src/utils/find-target-options'
|
||||||
|
);
|
||||||
const found = await findBuildConfig(tree, {
|
const found = await findBuildConfig(tree, {
|
||||||
project: options.project,
|
project: options.project,
|
||||||
buildTarget: options.buildTarget,
|
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 { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
||||||
import reactInitGenerator from './init';
|
import reactInitGenerator from './init';
|
||||||
import { InitSchema } from './schema';
|
import { InitSchema } from './schema';
|
||||||
@ -30,4 +30,9 @@ describe('init', () => {
|
|||||||
await reactInitGenerator(tree, { ...schema, unitTestRunner: 'none' });
|
await reactInitGenerator(tree, { ...schema, unitTestRunner: 'none' });
|
||||||
expect(tree.exists('jest.config.js')).toEqual(false);
|
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 {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
|
ensurePackage,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
readWorkspaceConfiguration,
|
readWorkspaceConfiguration,
|
||||||
removeDependenciesFromPackageJson,
|
removeDependenciesFromPackageJson,
|
||||||
Tree,
|
Tree,
|
||||||
updateWorkspaceConfiguration,
|
updateWorkspaceConfiguration,
|
||||||
|
writeJson,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { webInitGenerator } from '@nrwl/web';
|
|
||||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
import {
|
import {
|
||||||
|
babelPresetReactVersion,
|
||||||
nxVersion,
|
nxVersion,
|
||||||
reactDomVersion,
|
reactDomVersion,
|
||||||
reactTestRendererVersion,
|
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) {
|
export async function reactInitGenerator(host: Tree, schema: InitSchema) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
setDefault(host);
|
setDefault(host);
|
||||||
|
|
||||||
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') {
|
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') {
|
||||||
|
await ensurePackage(host, '@nrwl/cypress', nxVersion);
|
||||||
|
const { cypressInitGenerator } = await import('@nrwl/cypress');
|
||||||
const cypressTask = cypressInitGenerator(host, {});
|
const cypressTask = cypressInitGenerator(host, {});
|
||||||
tasks.push(cypressTask);
|
tasks.push(cypressTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jack): We should be able to remove this generator and have react init everything.
|
if (!schema.skipPackageJson && !schema.skipBabelConfig) {
|
||||||
const initTask = await webInitGenerator(host, {
|
const installBabelTask = addDependenciesToPackageJson(
|
||||||
...schema,
|
host,
|
||||||
skipPackageJson: true,
|
{},
|
||||||
});
|
{
|
||||||
tasks.push(initTask);
|
'@babel/preset-react': babelPresetReactVersion,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
tasks.push(installBabelTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!schema.skipBabelConfig) {
|
||||||
|
initRootBabelConfig(host, schema);
|
||||||
|
}
|
||||||
|
|
||||||
if (!schema.skipPackageJson) {
|
if (!schema.skipPackageJson) {
|
||||||
const installTask = updateDependencies(host, schema);
|
const installTask = updateDependencies(host, schema);
|
||||||
tasks.push(installTask);
|
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,
|
Tree,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { assertValidStyle } from '../../../utils/assertion';
|
import { assertValidStyle } from '../../../utils/assertion';
|
||||||
import { NormalizedSchema } from '../library';
|
import { NormalizedSchema, Schema } from '../schema';
|
||||||
import { Schema } from '../schema';
|
|
||||||
|
|
||||||
export function normalizeOptions(
|
export function normalizeOptions(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -40,7 +39,9 @@ export function normalizeOptions(
|
|||||||
const normalized = {
|
const normalized = {
|
||||||
...options,
|
...options,
|
||||||
compiler: options.compiler ?? 'babel',
|
compiler: options.compiler ?? 'babel',
|
||||||
bundler: options.bundler ?? 'none',
|
bundler:
|
||||||
|
options.bundler ??
|
||||||
|
(options.buildable || options.publishable ? 'rollup' : 'none'),
|
||||||
fileName,
|
fileName,
|
||||||
routePath: `/${name}`,
|
routePath: `/${name}`,
|
||||||
name: projectName,
|
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,
|
createTreeWithEmptyWorkspace,
|
||||||
} from '@nrwl/devkit/testing';
|
} from '@nrwl/devkit/testing';
|
||||||
import { Linter } from '@nrwl/linter';
|
import { Linter } from '@nrwl/linter';
|
||||||
|
import { nxVersion } from '../../utils/versions';
|
||||||
import applicationGenerator from '../application/application';
|
import applicationGenerator from '../application/application';
|
||||||
import libraryGenerator from './library';
|
import libraryGenerator from './library';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
@ -37,6 +38,16 @@ describe('lib', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockedInstalledCypressVersion.mockReturnValue(10);
|
mockedInstalledCypressVersion.mockReturnValue(10);
|
||||||
tree = createTreeWithEmptyV1Workspace();
|
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', () => {
|
describe('not nested', () => {
|
||||||
@ -726,7 +737,6 @@ describe('lib', () => {
|
|||||||
describe('--skipPackageJson', () => {
|
describe('--skipPackageJson', () => {
|
||||||
it('should not add dependencies to package.json when true', async () => {
|
it('should not add dependencies to package.json when true', async () => {
|
||||||
// ARRANGE
|
// ARRANGE
|
||||||
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
||||||
const packageJsonBeforeGenerator = tree.read('package.json', 'utf-8');
|
const packageJsonBeforeGenerator = tree.read('package.json', 'utf-8');
|
||||||
// ACT
|
// ACT
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
|
|||||||
@ -1,64 +1,32 @@
|
|||||||
import {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
applyChangesToString,
|
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
|
ensurePackage,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
getWorkspaceLayout,
|
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
names,
|
|
||||||
offsetFromRoot,
|
|
||||||
toJS,
|
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
} from '@nrwl/devkit';
|
} 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 { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getRelativePathToRootTsConfig,
|
nxVersion,
|
||||||
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 {
|
|
||||||
reactDomVersion,
|
reactDomVersion,
|
||||||
reactRouterDomVersion,
|
|
||||||
reactVersion,
|
reactVersion,
|
||||||
typesReactRouterDomVersion,
|
swcCoreVersion,
|
||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import componentGenerator from '../component/component';
|
import componentGenerator from '../component/component';
|
||||||
import initGenerator from '../init/init';
|
import initGenerator from '../init/init';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { updateJestConfigContent } from '../../utils/jest-utils';
|
import { updateJestConfigContent } from '../../utils/jest-utils';
|
||||||
import { viteConfigurationGenerator, vitestGenerator } from '@nrwl/vite';
|
|
||||||
import { normalizeOptions } from './lib/normalize-options';
|
import { normalizeOptions } from './lib/normalize-options';
|
||||||
|
import { addRollupBuildTarget } from './lib/add-rollup-build-target';
|
||||||
export interface NormalizedSchema extends Schema {
|
import { addLinting } from './lib/add-linting';
|
||||||
name: string;
|
import { updateAppRoutes } from './lib/update-app-routes';
|
||||||
fileName: string;
|
import { createFiles } from './lib/create-files';
|
||||||
projectRoot: string;
|
import { updateBaseTsConfig } from './lib/update-base-tsconfig';
|
||||||
routePath: string;
|
|
||||||
projectDirectory: string;
|
|
||||||
parsedTags: string[];
|
|
||||||
appMain?: string;
|
|
||||||
appSourceRoot?: string;
|
|
||||||
libsDir?: string;
|
|
||||||
unitTestRunner: 'jest' | 'vitest' | 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function libraryGenerator(host: Tree, schema: Schema) {
|
export async function libraryGenerator(host: Tree, schema: Schema) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
@ -82,7 +50,18 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
});
|
});
|
||||||
tasks.push(initTask);
|
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);
|
const lintTask = await addLinting(host, options);
|
||||||
tasks.push(lintTask);
|
tasks.push(lintTask);
|
||||||
@ -93,7 +72,10 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
updateBaseTsConfig(host, options);
|
updateBaseTsConfig(host, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up build target
|
||||||
if (options.buildable && options.bundler === 'vite') {
|
if (options.buildable && options.bundler === 'vite') {
|
||||||
|
await ensurePackage(host, '@nrwl/vite', nxVersion);
|
||||||
|
const { viteConfigurationGenerator } = await import('@nrwl/vite');
|
||||||
const viteTask = await viteConfigurationGenerator(host, {
|
const viteTask = await viteConfigurationGenerator(host, {
|
||||||
uiFramework: 'react',
|
uiFramework: 'react',
|
||||||
project: options.name,
|
project: options.name,
|
||||||
@ -103,9 +85,16 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
includeVitest: true,
|
includeVitest: true,
|
||||||
});
|
});
|
||||||
tasks.push(viteTask);
|
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') {
|
if (options.unitTestRunner === 'jest') {
|
||||||
|
await ensurePackage(host, '@nrwl/jest', nxVersion);
|
||||||
|
const { jestProjectGenerator } = await import('@nrwl/jest');
|
||||||
|
|
||||||
const jestTask = await jestProjectGenerator(host, {
|
const jestTask = await jestProjectGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
project: options.name,
|
project: options.name,
|
||||||
@ -129,6 +118,8 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
options.unitTestRunner === 'vitest' &&
|
options.unitTestRunner === 'vitest' &&
|
||||||
options.bundler !== 'vite' // tests are already configured if bundler is vite
|
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, {
|
const vitestTask = await vitestGenerator(host, {
|
||||||
uiFramework: 'react',
|
uiFramework: 'react',
|
||||||
project: options.name,
|
project: options.name,
|
||||||
@ -155,11 +146,14 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.publishable || options.buildable) {
|
if (options.publishable || options.buildable) {
|
||||||
updateLibPackageNpmScope(host, options);
|
updateJson(host, `${options.projectRoot}/package.json`, (json) => {
|
||||||
|
json.name = options.importPath;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.skipPackageJson) {
|
if (!options.skipPackageJson) {
|
||||||
const installTask = await addDependenciesToPackageJson(
|
const installReactTask = await addDependenciesToPackageJson(
|
||||||
host,
|
host,
|
||||||
{
|
{
|
||||||
react: reactVersion,
|
react: reactVersion,
|
||||||
@ -167,7 +161,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
},
|
},
|
||||||
options.compiler === 'swc' ? { '@swc/core': swcCoreVersion } : {}
|
options.compiler === 'swc' ? { '@swc/core': swcCoreVersion } : {}
|
||||||
);
|
);
|
||||||
tasks.push(installTask);
|
tasks.push(installReactTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
const routeTask = updateAppRoutes(host, options);
|
const routeTask = updateAppRoutes(host, options);
|
||||||
@ -180,281 +174,5 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
return runTasksInSerial(...tasks);
|
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 default libraryGenerator;
|
||||||
export const librarySchematic = convertNxGenerator(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';
|
import { SupportedStyles } from '../../../typings/style';
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
@ -28,3 +28,17 @@ export interface Schema {
|
|||||||
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
unitTestRunner?: 'jest' | 'vitest' | 'none';
|
||||||
minimal?: boolean;
|
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,
|
visitNotIgnoredFiles,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { basename, join } from 'path';
|
import { basename, join } from 'path';
|
||||||
import {
|
|
||||||
findStorybookAndBuildTargetsAndCompiler,
|
|
||||||
isTheFileAStory,
|
|
||||||
} from '@nrwl/storybook/src/utils/utilities';
|
|
||||||
import minimatch = require('minimatch');
|
import minimatch = require('minimatch');
|
||||||
|
|
||||||
export interface StorybookStoriesSchema {
|
export interface StorybookStoriesSchema {
|
||||||
@ -29,7 +25,13 @@ export interface StorybookStoriesSchema {
|
|||||||
ignorePaths?: string[];
|
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;
|
let projectDir: string;
|
||||||
if (config.projectType === 'application') {
|
if (config.projectType === 'application') {
|
||||||
const { nextBuildTarget } = findStorybookAndBuildTargetsAndCompiler(
|
const { nextBuildTarget } = findStorybookAndBuildTargetsAndCompiler(
|
||||||
@ -79,12 +81,16 @@ export async function createAllStories(
|
|||||||
cypressProject?: string,
|
cypressProject?: string,
|
||||||
ignorePaths?: string[]
|
ignorePaths?: string[]
|
||||||
) {
|
) {
|
||||||
|
const { isTheFileAStory } = await import(
|
||||||
|
'@nrwl/storybook/src/utils/utilities'
|
||||||
|
);
|
||||||
const projects = getProjects(tree);
|
const projects = getProjects(tree);
|
||||||
const projectConfiguration = projects.get(projectName);
|
const projectConfiguration = projects.get(projectName);
|
||||||
const { sourceRoot, root } = projectConfiguration;
|
const { sourceRoot, root } = projectConfiguration;
|
||||||
let componentPaths: string[] = [];
|
let componentPaths: string[] = [];
|
||||||
|
|
||||||
visitNotIgnoredFiles(tree, projectRootPath(projectConfiguration), (path) => {
|
const projectPath = await projectRootPath(tree, projectConfiguration);
|
||||||
|
visitNotIgnoredFiles(tree, projectPath, (path) => {
|
||||||
// Ignore private files starting with "_".
|
// Ignore private files starting with "_".
|
||||||
if (basename(path).startsWith('_')) return;
|
if (basename(path).startsWith('_')) return;
|
||||||
|
|
||||||
|
|||||||
@ -2,14 +2,18 @@ import { StorybookConfigureSchema } from './schema';
|
|||||||
import storiesGenerator from '../stories/stories';
|
import storiesGenerator from '../stories/stories';
|
||||||
import {
|
import {
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
|
ensurePackage,
|
||||||
logger,
|
logger,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { configurationGenerator } from '@nrwl/storybook';
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { getE2eProjectName } from '@nrwl/cypress/src/utils/project-name';
|
|
||||||
|
|
||||||
async function generateStories(host: Tree, schema: StorybookConfigureSchema) {
|
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 projectConfig = readProjectConfiguration(host, schema.name);
|
||||||
const cypressProject = getE2eProjectName(
|
const cypressProject = getE2eProjectName(
|
||||||
schema.name,
|
schema.name,
|
||||||
@ -30,6 +34,9 @@ export async function storybookConfigurationGenerator(
|
|||||||
host: Tree,
|
host: Tree,
|
||||||
schema: StorybookConfigureSchema
|
schema: StorybookConfigureSchema
|
||||||
) {
|
) {
|
||||||
|
await ensurePackage(host, '@nrwl/storybook', nxVersion);
|
||||||
|
const { configurationGenerator } = await import('@nrwl/storybook');
|
||||||
|
|
||||||
let bundler = schema.bundler ?? 'webpack';
|
let bundler = schema.bundler ?? 'webpack';
|
||||||
const projectConfig = readProjectConfiguration(host, schema.name);
|
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,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nrwl/devkit';
|
} 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 { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
|
||||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||||
import { StringLiteral } from 'typescript';
|
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 reactVersion = '18.2.0';
|
||||||
export const reactDomVersion = '18.2.0';
|
export const reactDomVersion = '18.2.0';
|
||||||
export const reactIsVersion = '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 typesReactVersion = '18.0.25';
|
||||||
export const typesReactDomVersion = '18.0.9';
|
export const typesReactDomVersion = '18.0.9';
|
||||||
export const typesReactIsVersion = '17.0.3';
|
export const typesReactIsVersion = '17.0.3';
|
||||||
|
|
||||||
export const typesNodeVersion = '18.11.9';
|
export const typesNodeVersion = '18.11.9';
|
||||||
|
|
||||||
|
export const babelPresetReactVersion = '^7.14.5';
|
||||||
|
|
||||||
export const styledComponentsVersion = '5.3.6';
|
export const styledComponentsVersion = '5.3.6';
|
||||||
export const typesStyledComponentsVersion = '5.1.26';
|
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/schema';
|
||||||
export * from './src/executors/rollup/rollup.impl';
|
export * from './src/executors/rollup/rollup.impl';
|
||||||
|
|||||||
@ -27,9 +27,7 @@ export async function rollupInitGenerator(tree: Tree, schema: Schema) {
|
|||||||
'swc-loader': swcLoaderVersion,
|
'swc-loader': swcLoaderVersion,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if (schema.compiler === 'tsc') {
|
|
||||||
task = addDependenciesToPackageJson(tree, {}, { tslib: tsLibVersion });
|
task = addDependenciesToPackageJson(tree, {}, { tslib: tsLibVersion });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
export * from './src/utils/config';
|
export * from './src/utils/config';
|
||||||
|
export * from './src/generators/init/init';
|
||||||
export * from './src/generators/webpack-project/webpack-project';
|
export * from './src/generators/webpack-project/webpack-project';
|
||||||
export type { WebDevServerOptions } from './src/executors/dev-server/schema';
|
export type { WebDevServerOptions } from './src/executors/dev-server/schema';
|
||||||
export * from './src/executors/dev-server/dev-server.impl';
|
export * from './src/executors/dev-server/dev-server.impl';
|
||||||
|
|||||||
@ -5,10 +5,10 @@ import {
|
|||||||
runExecutor,
|
runExecutor,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import * as chalk from 'chalk';
|
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 { WebpackExecutorOptions } from '../webpack/schema';
|
||||||
import { WebSsrDevServerOptions } from './schema';
|
import { TargetOptions, WebSsrDevServerOptions } from './schema';
|
||||||
import { waitUntilServerIsListening } from './lib/wait-until-server-is-listening';
|
import { waitUntilServerIsListening } from './lib/wait-until-server-is-listening';
|
||||||
|
|
||||||
export async function* ssrDevServerExecutor(
|
export async function* ssrDevServerExecutor(
|
||||||
@ -29,6 +29,7 @@ export async function* ssrDevServerExecutor(
|
|||||||
const runBrowser = await runExecutor<{
|
const runBrowser = await runExecutor<{
|
||||||
success: boolean;
|
success: boolean;
|
||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
|
options: TargetOptions;
|
||||||
}>(
|
}>(
|
||||||
browserTarget,
|
browserTarget,
|
||||||
{ ...browserOptions, ...options.browserTargetOptions },
|
{ ...browserOptions, ...options.browserTargetOptions },
|
||||||
@ -37,6 +38,7 @@ export async function* ssrDevServerExecutor(
|
|||||||
const runServer = await runExecutor<{
|
const runServer = await runExecutor<{
|
||||||
success: boolean;
|
success: boolean;
|
||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
|
options: TargetOptions;
|
||||||
}>(
|
}>(
|
||||||
serverTarget,
|
serverTarget,
|
||||||
{ ...serverOptions, ...options.serverTargetOptions },
|
{ ...serverOptions, ...options.serverTargetOptions },
|
||||||
|
|||||||
@ -5,24 +5,31 @@ import {
|
|||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nrwl/devkit';
|
} 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 { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
||||||
|
|
||||||
|
import { Schema } from './schema';
|
||||||
import {
|
import {
|
||||||
|
reactRefreshVersion,
|
||||||
|
reactRefreshWebpackPluginVersion,
|
||||||
|
svgrWebpackVersion,
|
||||||
swcHelpersVersion,
|
swcHelpersVersion,
|
||||||
swcLoaderVersion,
|
swcLoaderVersion,
|
||||||
tsLibVersion,
|
tsLibVersion,
|
||||||
|
tsQueryVersion,
|
||||||
|
urlLoaderVersion,
|
||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import { addBabelInputs } from '@nrwl/js/src/utils/add-babel-inputs';
|
import { addBabelInputs } from '@nrwl/js/src/utils/add-babel-inputs';
|
||||||
|
|
||||||
export async function webpackInitGenerator(tree: Tree, schema: Schema) {
|
export async function webpackInitGenerator(tree: Tree, schema: Schema) {
|
||||||
let task: GeneratorCallback;
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
if (schema.compiler === 'babel') {
|
if (schema.compiler === 'babel') {
|
||||||
addBabelInputs(tree);
|
addBabelInputs(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.compiler === 'swc') {
|
if (schema.compiler === 'swc') {
|
||||||
task = addDependenciesToPackageJson(
|
const swcInstallTask = addDependenciesToPackageJson(
|
||||||
tree,
|
tree,
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@ -31,17 +38,39 @@ export async function webpackInitGenerator(tree: Tree, schema: Schema) {
|
|||||||
'swc-loader': swcLoaderVersion,
|
'swc-loader': swcLoaderVersion,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
tasks.push(swcInstallTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.compiler === 'tsc') {
|
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) {
|
if (!schema.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
return task;
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default webpackInitGenerator;
|
export default webpackInitGenerator;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
export interface Schema {
|
export interface Schema {
|
||||||
compiler?: 'babel' | 'swc' | 'tsc';
|
compiler?: 'babel' | 'swc' | 'tsc';
|
||||||
|
uiFramework?: 'react' | 'none';
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,12 @@
|
|||||||
"description": "Init Webpack Plugin.",
|
"description": "Init Webpack Plugin.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"uiFramework": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "UI Framework to use for Vite.",
|
||||||
|
"enum": ["react", "none"],
|
||||||
|
"x-prompt": "What UI framework plugin should Webpack use?"
|
||||||
|
},
|
||||||
"compiler": {
|
"compiler": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["babel", "swc", "tsc"],
|
"enum": ["babel", "swc", "tsc"],
|
||||||
|
|||||||
@ -3,3 +3,10 @@ export const nxVersion = require('../../package.json').version;
|
|||||||
export const swcLoaderVersion = '0.1.15';
|
export const swcLoaderVersion = '0.1.15';
|
||||||
export const swcHelpersVersion = '~0.4.11';
|
export const swcHelpersVersion = '~0.4.11';
|
||||||
export const tsLibVersion = '^2.3.0';
|
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/devkit"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"command": "node ./scripts/add-dependency-to-build.js workspace @nrwl/jest"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"command": "node ./scripts/add-dependency-to-build.js workspace @nrwl/linter"
|
"command": "node ./scripts/add-dependency-to-build.js workspace @nrwl/linter"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,20 @@
|
|||||||
import {
|
import {
|
||||||
Tree,
|
addDependenciesToPackageJson,
|
||||||
|
addProjectConfiguration,
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
|
ensurePackage,
|
||||||
|
extractLayoutDirectory,
|
||||||
|
formatFiles,
|
||||||
|
generateFiles,
|
||||||
|
GeneratorCallback,
|
||||||
|
getWorkspaceLayout,
|
||||||
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
generateFiles,
|
|
||||||
toJS,
|
|
||||||
getWorkspaceLayout,
|
|
||||||
addProjectConfiguration,
|
|
||||||
formatFiles,
|
|
||||||
updateJson,
|
|
||||||
GeneratorCallback,
|
|
||||||
joinPathFragments,
|
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
addDependenciesToPackageJson,
|
toJS,
|
||||||
extractLayoutDirectory,
|
Tree,
|
||||||
|
updateJson,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { getImportPath } from 'nx/src/utils/path';
|
import { getImportPath } from 'nx/src/utils/path';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
@ -25,11 +26,6 @@ import {
|
|||||||
import { nxVersion } from '../../utils/versions';
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { Schema } from './schema';
|
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 {
|
export interface NormalizedSchema extends Schema {
|
||||||
name: string;
|
name: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
@ -74,10 +70,12 @@ function addProject(tree: Tree, options: NormalizedSchema) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addLint(
|
export async function addLint(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: NormalizedSchema
|
options: NormalizedSchema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
|
await ensurePackage(tree, '@nrwl/linter', nxVersion);
|
||||||
|
const { lintProjectGenerator } = require('@nrwl/linter');
|
||||||
return lintProjectGenerator(tree, {
|
return lintProjectGenerator(tree, {
|
||||||
project: options.name,
|
project: options.name,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
@ -178,6 +176,8 @@ async function addJest(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: NormalizedSchema
|
options: NormalizedSchema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
|
await ensurePackage(tree, '@nrwl/jest', nxVersion);
|
||||||
|
const { jestProjectGenerator } = require('@nrwl/jest');
|
||||||
return await jestProjectGenerator(tree, {
|
return await jestProjectGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
project: options.name,
|
project: options.name,
|
||||||
@ -232,7 +232,7 @@ function normalizeOptions(tree: Tree, options: Schema): NormalizedSchema {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!options.linter) {
|
if (!options.linter) {
|
||||||
options.linter = Linter.EsLint;
|
options.linter = 'eslint';
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||||
|
|||||||
@ -3,7 +3,21 @@ import { join } from 'path';
|
|||||||
|
|
||||||
// Ignore packages that are defined here per package
|
// Ignore packages that are defined here per package
|
||||||
const IGNORE_MATCHES_IN_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: [
|
||||||
'@angular-devkit/architect',
|
'@angular-devkit/architect',
|
||||||
'@angular-devkit/build-angular',
|
'@angular-devkit/build-angular',
|
||||||
@ -68,26 +82,30 @@ const IGNORE_MATCHES_IN_PACKAGE = {
|
|||||||
'webpack',
|
'webpack',
|
||||||
],
|
],
|
||||||
react: [
|
react: [
|
||||||
'babel-plugin-emotion',
|
// These are brought in by the webpack, rollup, or vite packages via init generators.
|
||||||
'babel-plugin-styled-components',
|
'@babel/preset-react',
|
||||||
'rollup',
|
'@module-federation/node',
|
||||||
'webpack',
|
'@phenomnomnominal/tsquery',
|
||||||
|
'@pmmmwh/react-refresh-webpack-plugin',
|
||||||
|
'@svgr/webpack',
|
||||||
'@swc/jest',
|
'@swc/jest',
|
||||||
'babel-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-loader',
|
||||||
|
'babel-plugin-emotion',
|
||||||
|
'babel-plugin-styled-components',
|
||||||
'css-loader',
|
'css-loader',
|
||||||
'less-loader',
|
'less-loader',
|
||||||
|
'react-refresh',
|
||||||
|
'rollup',
|
||||||
'sass',
|
'sass',
|
||||||
'sass-loader',
|
'sass-loader',
|
||||||
'style-loader',
|
'style-loader',
|
||||||
'stylus-loader',
|
'stylus-loader',
|
||||||
'swc-loader',
|
'swc-loader',
|
||||||
'tsconfig-paths-webpack-plugin',
|
'tsconfig-paths-webpack-plugin',
|
||||||
'@module-federation/node',
|
'url-loader',
|
||||||
|
'webpack',
|
||||||
|
'webpack-merge',
|
||||||
],
|
],
|
||||||
rollup: ['@swc/core'],
|
rollup: ['@swc/core'],
|
||||||
storybook: [
|
storybook: [
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user