fix(core): swc should be an optional peer dependency (#10461)

This commit is contained in:
Craigory Coppola 2022-05-26 12:09:27 -04:00 committed by GitHub
parent 33b5142969
commit c9897c61e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 196 additions and 69 deletions

View File

@ -45,11 +45,12 @@ export function addDependenciesToPackageJson(
return json; return json;
}); });
}
return (): void => { return (): void => {
installPackagesTask(tree); installPackagesTask(tree);
}; };
} }
return () => {};
}
/** /**
* Remove Dependencies and Dev Dependencies from package.json * Remove Dependencies and Dev Dependencies from package.json

View File

@ -2,7 +2,7 @@ import { addDependenciesToPackageJson, Tree } from '@nrwl/devkit';
import { swcCliVersion, swcCoreVersion, swcHelpersVersion } from '../versions'; import { swcCliVersion, swcCoreVersion, swcHelpersVersion } from '../versions';
export function addSwcDependencies(tree: Tree) { export function addSwcDependencies(tree: Tree) {
addDependenciesToPackageJson( return addDependenciesToPackageJson(
tree, tree,
{ {
'@swc/helpers': swcHelpersVersion, '@swc/helpers': swcHelpersVersion,

View File

@ -1,5 +1,6 @@
export { swcCoreVersion } from 'nx/src/utils/versions';
export const nxVersion = require('../../package.json').version; export const nxVersion = require('../../package.json').version;
export const swcCoreVersion = '~1.2.143';
export const swcCliVersion = '~0.1.55'; export const swcCliVersion = '~0.1.55';
export const swcHelpersVersion = '~0.3.3'; export const swcHelpersVersion = '~0.3.3';

View File

@ -64,6 +64,12 @@
"version": "13.3.0-beta.0", "version": "13.3.0-beta.0",
"description": "Update eslint-rules jest.config.js in order to support ESLint v8 exports mapping, remove category field", "description": "Update eslint-rules jest.config.js in order to support ESLint v8 exports mapping, remove category field",
"factory": "./src/migrations/update-13-3-0/eslint-8-updates" "factory": "./src/migrations/update-13-3-0/eslint-8-updates"
},
"add-swc-deps": {
"cli": "nx",
"version": "14-1-9-beta.0",
"description": "Adds @swc/core and @swc-node as a dev dep if you are using them",
"factory": "./src/migrations/update-14-1-9/add-swc-deps-if-needed"
} }
}, },
"packageJsonUpdates": { "packageJsonUpdates": {

View File

@ -36,6 +36,7 @@
"@nrwl/devkit": "file:../devkit", "@nrwl/devkit": "file:../devkit",
"@nrwl/jest": "file:../jest", "@nrwl/jest": "file:../jest",
"@phenomnomnominal/tsquery": "4.1.1", "@phenomnomnominal/tsquery": "4.1.1",
"nx": "file:../nx",
"tmp": "~0.2.1", "tmp": "~0.2.1",
"tslib": "^2.3.0" "tslib": "^2.3.0"
}, },

View File

@ -1,4 +1,5 @@
import { import {
addDependenciesToPackageJson,
addProjectConfiguration, addProjectConfiguration,
convertNxGenerator, convertNxGenerator,
formatFiles, formatFiles,
@ -14,10 +15,11 @@ 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';
export const WORKSPACE_RULES_PROJECT_NAME = 'eslint-rules'; export const WORKSPACE_RULES_PROJECT_NAME = 'eslint-rules';
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) {
// Noop if the workspace rules project already exists // Noop if the workspace rules project already exists
@ -54,7 +56,7 @@ export async function lintWorkspaceRulesProjectGenerator(tree: Tree) {
}); });
// Add jest to the project and return installation task // Add jest to the project and return installation task
const jestInstallationTask = await jestProjectGenerator(tree, { const installTask = await jestProjectGenerator(tree, {
project: WORKSPACE_RULES_PROJECT_NAME, project: WORKSPACE_RULES_PROJECT_NAME,
supportTsx: false, supportTsx: false,
skipSerializers: true, skipSerializers: true,
@ -62,6 +64,13 @@ export async function lintWorkspaceRulesProjectGenerator(tree: Tree) {
compiler: 'tsc', compiler: 'tsc',
}); });
// Add swc dependencies
addDependenciesToPackageJson(
tree,
{},
{ '@swc-node/register': swcNodeVersion, '@swc/core': swcCoreVersion }
);
// Add extra config to the jest.config.ts file to allow ESLint 8 exports mapping to work with jest // Add extra config to the jest.config.ts file to allow ESLint 8 exports mapping to work with jest
addPropertyToJestConfig( addPropertyToJestConfig(
tree, tree,
@ -74,7 +83,7 @@ export async function lintWorkspaceRulesProjectGenerator(tree: Tree) {
await formatFiles(tree); await formatFiles(tree);
return jestInstallationTask; return installTask;
} }
export const lintWorkspaceRulesProjectSchematic = convertNxGenerator( export const lintWorkspaceRulesProjectSchematic = convertNxGenerator(

View File

@ -0,0 +1,17 @@
import { addDependenciesToPackageJson, formatFiles, Tree } from '@nrwl/devkit';
import { swcCoreVersion, swcNodeVersion } from 'nx/src/utils/versions';
import { WORKSPACE_PLUGIN_DIR } from '../../generators/workspace-rules-project/workspace-rules-project';
export default async function addSwcNodeIfNeeded(tree: Tree) {
try {
if (tree.exists(WORKSPACE_PLUGIN_DIR)) {
addDependenciesToPackageJson(
tree,
{},
{ '@swc-node/register': swcNodeVersion, '@swc/core': swcCoreVersion }
);
await formatFiles(tree);
return;
}
} catch {}
}

View File

@ -14,6 +14,12 @@
"version": "11.0.17", "version": "11.0.17",
"description": "Update schema versions for executors and generators", "description": "Update schema versions for executors and generators",
"factory": "./src/migrations/update-11-0-0/update-schema-version-for-executors-and-generators" "factory": "./src/migrations/update-11-0-0/update-schema-version-for-executors-and-generators"
},
"add-swc-deps": {
"cli": "nx",
"version": "14-1-9-beta.0",
"description": "Adds @swc/core and @swc-node as a dev dep if you are using them",
"factory": "./src/migrations/update-14-1-9/add-swc-deps-if-needed"
} }
} }
} }

View File

@ -1,4 +1,3 @@
import type { Tree } from '@nrwl/devkit';
import { import {
addDependenciesToPackageJson, addDependenciesToPackageJson,
convertNxGenerator, convertNxGenerator,
@ -6,21 +5,25 @@ import {
generateFiles, generateFiles,
GeneratorCallback, GeneratorCallback,
getWorkspaceLayout, getWorkspaceLayout,
installPackagesTask,
joinPathFragments, joinPathFragments,
names, names,
normalizePath, normalizePath,
readProjectConfiguration, readProjectConfiguration,
Tree,
updateProjectConfiguration, updateProjectConfiguration,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import type { Schema } from './schema';
import { nxVersion } from '../../utils/versions';
import * as path from 'path';
import { libraryGenerator } from '@nrwl/js'; import { libraryGenerator } from '@nrwl/js';
import { e2eProjectGenerator } from '../e2e-project/e2e'; import { addSwcDependencies } from '@nrwl/js/src/utils/swc/add-swc-dependencies';
import { generatorGenerator } from '../generator/generator'; import { swcNodeVersion } from 'nx/src/utils/versions';
import { executorGenerator } from '../executor/executor'; import * as path from 'path';
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
import { nxVersion } from '../../utils/versions';
import { e2eProjectGenerator } from '../e2e-project/e2e';
import { executorGenerator } from '../executor/executor';
import { generatorGenerator } from '../generator/generator';
import type { Schema } from './schema';
interface NormalizedSchema extends Schema { interface NormalizedSchema extends Schema {
name: string; name: string;
fileName: string; fileName: string;
@ -125,7 +128,6 @@ function updateWorkspaceJson(host: Tree, options: NormalizedSchema) {
export async function pluginGenerator(host: Tree, schema: Schema) { export async function pluginGenerator(host: Tree, schema: Schema) {
const options = normalizeOptions(host, schema); const options = normalizeOptions(host, schema);
const tasks: GeneratorCallback[] = [];
const libraryTask = await libraryGenerator(host, { const libraryTask = await libraryGenerator(host, {
...schema, ...schema,
@ -134,19 +136,21 @@ export async function pluginGenerator(host: Tree, schema: Schema) {
importPath: options.npmPackageName, importPath: options.npmPackageName,
}); });
tasks.push(libraryTask); addDependenciesToPackageJson(
const installTask = addDependenciesToPackageJson(
host, host,
{}, {},
{ {
'@nrwl/devkit': nxVersion, '@nrwl/devkit': nxVersion,
'@nrwl/jest': nxVersion, '@nrwl/jest': nxVersion,
'@nrwl/js': nxVersion, '@nrwl/js': nxVersion,
'@swc-node/register': swcNodeVersion,
tslib: '^2.0.0', tslib: '^2.0.0',
} }
); );
tasks.push(installTask);
// Ensures Swc Deps are installed to handle running
// local plugin generators and executors
addSwcDependencies(host);
await addFiles(host, options); await addFiles(host, options);
updateWorkspaceJson(host, options); updateWorkspaceJson(host, options);
@ -161,7 +165,7 @@ export async function pluginGenerator(host: Tree, schema: Schema) {
await formatFiles(host); await formatFiles(host);
return runTasksInSerial(...tasks); return () => installPackagesTask(host);
} }
function resolvePackageName(npmScope: string, name: string): string { function resolvePackageName(npmScope: string, name: string): string {

View File

@ -0,0 +1,17 @@
import {
addDependenciesToPackageJson,
formatFiles,
installPackagesTask,
Tree,
} from '@nrwl/devkit';
import { swcCoreVersion, swcNodeVersion } from 'nx/src/utils/versions';
export default async function addSwcNodeIfNeeded(tree: Tree) {
addDependenciesToPackageJson(
tree,
{},
{ '@swc-node/register': swcNodeVersion, '@swc/core': swcCoreVersion }
);
await formatFiles(tree);
return installPackagesTask(tree);
}

View File

@ -32,8 +32,6 @@
"homepage": "https://nx.dev", "homepage": "https://nx.dev",
"dependencies": { "dependencies": {
"@parcel/watcher": "2.0.4", "@parcel/watcher": "2.0.4",
"@swc-node/register": "^1.4.2",
"@swc/core": "^1.2.173",
"chalk": "4.1.0", "chalk": "4.1.0",
"chokidar": "^3.5.1", "chokidar": "^3.5.1",
"cli-cursor": "3.1.0", "cli-cursor": "3.1.0",
@ -61,6 +59,18 @@
"yargs": "^17.4.0", "yargs": "^17.4.0",
"yargs-parser": "21.0.1" "yargs-parser": "21.0.1"
}, },
"peerDependencies": {
"@swc-node/register": "^1.4.2",
"@swc/core": "^1.2.173"
},
"peerDependenciesMeta": {
"@swc-node/register": {
"optional": true
},
"@swc/core": {
"optional": true
}
},
"nx-migrations": { "nx-migrations": {
"migrations": "./migrations.json", "migrations": "./migrations.json",
"packageGroup": [ "packageGroup": [

View File

@ -1,4 +1,5 @@
import { join } from 'path'; import { join } from 'path';
import { logger, NX_PREFIX, stripIndent } from './logger';
/** /**
* Optionally, if swc-node and tsconfig-paths are available in the current workspace, apply the require * Optionally, if swc-node and tsconfig-paths are available in the current workspace, apply the require
@ -7,22 +8,72 @@ import { join } from 'path';
* If ts-node and tsconfig-paths are not available, the user can still provide an index.js file in * If ts-node and tsconfig-paths are not available, the user can still provide an index.js file in
* the root of their project and the fundamentals will still work (but * the root of their project and the fundamentals will still work (but
* workspace path mapping will not, for example). * workspace path mapping will not, for example).
*
* @returns cleanup function
*/ */
export const registerTsProject = ( export const registerTsProject = (
path: string, path: string,
configFilename = 'tsconfig.json' configFilename = 'tsconfig.json'
) => { ): (() => void) => {
// Function to register transpiler that returns cleanup function
let registerTranspiler: () => () => void;
const tsConfigPath = join(path, configFilename);
const cleanupFunctions = [registerTsConfigPaths(tsConfigPath)];
const swcNodeInstalled = packageIsInstalled('@swc-node/register');
if (swcNodeInstalled) {
// These are requires to prevent it from registering when it shouldn't // These are requires to prevent it from registering when it shouldn't
const { register } = require('@swc-node/register/register'); const { register } =
require('@swc-node/register/register') as typeof import('@swc-node/register/register');
const { const {
readDefaultTsConfig, readDefaultTsConfig,
} = require('@swc-node/register/read-default-tsconfig'); } = require('@swc-node/register/read-default-tsconfig');
try {
const tsConfigPath = join(path, configFilename);
const tsConfig = readDefaultTsConfig(tsConfigPath); const tsConfig = readDefaultTsConfig(tsConfigPath);
register(tsConfig); registerTranspiler = () => register(tsConfig);
} else {
// We can fall back on ts-node if its available
const tsNodeInstalled = packageIsInstalled('ts-node/register');
if (tsNodeInstalled) {
warnTsNodeUsage();
const { register } = require('ts-node') as typeof import('ts-node');
// ts-node doesn't provide a cleanup method
registerTranspiler = () => {
register({
project: tsConfigPath,
transpileOnly: true,
compilerOptions: {
module: 'commonjs',
},
});
return () => {};
};
}
}
if (registerTranspiler) {
cleanupFunctions.push(registerTranspiler());
} else {
warnNoTranspiler();
}
// Overall cleanup method cleans up tsconfig path resolution
// as well as ts transpiler
return () => {
for (const f of cleanupFunctions) {
f();
}
};
};
/**
* @param tsConfigPath Adds the paths from a tsconfig file into node resolutions
* @returns cleanup function
*/
export function registerTsConfigPaths(tsConfigPath): () => void {
try {
/** /**
* Load the ts config from the source project * Load the ts config from the source project
*/ */
@ -38,6 +89,38 @@ export const registerTsProject = (
paths: tsConfigResult.paths, paths: tsConfigResult.paths,
}); });
} }
} catch (err) {} } catch (err) {
warnNoTsconfigPaths();
}
return () => {}; return () => {};
}; }
function warnTsNodeUsage() {
logger.warn(
stripIndent(`${NX_PREFIX} Falling back to ts-node for local typescript execution. This may be a little slower.
- To fix this, ensure @swc-node/register and @swc/core have been installed`)
);
}
function warnNoTsconfigPaths() {
logger.warn(
stripIndent(`${NX_PREFIX} Unable to load tsconfig-paths, workspace libraries may be inaccessible.
- To fix this, install tsconfig-paths with npm/yarn/pnpm`)
);
}
function warnNoTranspiler() {
logger.warn(
stripIndent(`${NX_PREFIX} Unable to locate swc-node or ts-node. Nx will be unable to run local ts files without transpiling.
- To fix this, ensure @swc-node/register and @swc/core have been installed`)
);
}
function packageIsInstalled(m: string) {
try {
const p = require.resolve(m);
return true;
} catch {
return false;
}
}

View File

@ -7,3 +7,5 @@ export const tslintVersion = '~6.1.0';
export const typescriptESLintVersion = '~5.18.0'; export const typescriptESLintVersion = '~5.18.0';
export const eslintVersion = '~8.12.0'; export const eslintVersion = '~8.12.0';
export const eslintConfigPrettierVersion = '8.1.0'; export const eslintConfigPrettierVersion = '8.1.0';
export const swcNodeVersion = '^1.4.2';
export const swcCoreVersion = '^1.2.173';

View File

@ -1,31 +1 @@
export interface PluginGenerator { export * from 'nx/src/utils/plugins/models';
factory: string;
schema: string;
description: string;
aliases: string;
hidden: boolean;
}
export interface PluginExecutor {
implementation: string;
schema: string;
description: string;
}
export interface PluginCapabilities {
name: string;
executors: { [name: string]: PluginExecutor };
generators: { [name: string]: PluginGenerator };
}
export interface CorePlugin {
name: string;
capabilities: 'executors' | 'generators' | 'executors,generators';
link?: string;
}
export interface CommunityPlugin {
name: string;
url: string;
description: string;
}

View File

@ -48,7 +48,7 @@ const argv = require('yargs')
.map((name) => ({ name })) .map((name) => ({ name }))
.map(async (project) => { .map(async (project) => {
const projectPath = join(packagesDirectory, project.name); const projectPath = join(packagesDirectory, project.name);
const { dependencies } = JSON.parse( const { dependencies, peerDependencies } = JSON.parse(
readFileSync(`${projectPath}/package.json`).toString() readFileSync(`${projectPath}/package.json`).toString()
); );
@ -56,7 +56,7 @@ const argv = require('yargs')
? await getMissingDependencies( ? await getMissingDependencies(
project.name, project.name,
projectPath, projectPath,
dependencies, { ...dependencies, ...(peerDependencies || {}) },
argv.verbose argv.verbose
) )
: []; : [];

View File

@ -101,6 +101,7 @@ const IGNORE_MATCHES = {
'@angular-devkit/core', '@angular-devkit/core',
'@angular-devkit/architect', '@angular-devkit/architect',
'@angular/cli', '@angular/cli',
'ts-node', // We *may* fall back on ts-node, but we want to encourage the use of @swc-node instead so we don't explicitly list ts-node as an optional dep
], ],
web: [ web: [
// we don't want to bloat the install of @nrwl/web by including @swc/core and swc-loader as a dependency. // we don't want to bloat the install of @nrwl/web by including @swc/core and swc-loader as a dependency.
@ -121,7 +122,6 @@ const IGNORE_MATCHES = {
'@nrwl/jest', '@nrwl/jest',
'@nrwl/linter', '@nrwl/linter',
'tsconfig-paths', 'tsconfig-paths',
'@swc-node/register',
], ],
nest: ['semver'], nest: ['semver'],
'make-angular-cli-faster': ['@angular/core'], 'make-angular-cli-faster': ['@angular/core'],