Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

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

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions packages/devkit/src/utils/package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ export function addDependenciesToPackageJson(

return json;
});
return (): void => {
installPackagesTask(tree);
};
}
return (): void => {
installPackagesTask(tree);
};
return () => {};
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/js/src/utils/swc/add-swc-dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { addDependenciesToPackageJson, Tree } from '@nrwl/devkit';
import { swcCliVersion, swcCoreVersion, swcHelpersVersion } from '../versions';

export function addSwcDependencies(tree: Tree) {
addDependenciesToPackageJson(
return addDependenciesToPackageJson(
tree,
{
'@swc/helpers': swcHelpersVersion,
Expand Down
3 changes: 2 additions & 1 deletion packages/js/src/utils/versions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { swcCoreVersion } from 'nx/src/utils/versions';

export const nxVersion = require('../../package.json').version;

export const swcCoreVersion = '~1.2.143';
export const swcCliVersion = '~0.1.55';
export const swcHelpersVersion = '~0.3.3';
6 changes: 6 additions & 0 deletions packages/linter/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@
"version": "13.3.0-beta.0",
"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"
},
"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": {
Expand Down
1 change: 1 addition & 0 deletions packages/linter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@nrwl/devkit": "file:../devkit",
"@nrwl/jest": "file:../jest",
"@phenomnomnominal/tsquery": "4.1.1",
"nx": "file:../nx",
"tmp": "~0.2.1",
"tslib": "^2.3.0"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
addDependenciesToPackageJson,
addProjectConfiguration,
convertNxGenerator,
formatFiles,
Expand All @@ -14,10 +15,11 @@ import { addPropertyToJestConfig, jestProjectGenerator } from '@nrwl/jest';
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
import { join } from 'path';
import { workspaceLintPluginDir } from '../../utils/workspace-lint-rules';
import { swcCoreVersion, swcNodeVersion } from 'nx/src/utils/versions';

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) {
// Noop if the workspace rules project already exists
Expand Down Expand Up @@ -54,14 +56,21 @@ export async function lintWorkspaceRulesProjectGenerator(tree: Tree) {
});

// Add jest to the project and return installation task
const jestInstallationTask = await jestProjectGenerator(tree, {
const installTask = await jestProjectGenerator(tree, {
project: WORKSPACE_RULES_PROJECT_NAME,
supportTsx: false,
skipSerializers: true,
setupFile: 'none',
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
addPropertyToJestConfig(
tree,
Expand All @@ -74,7 +83,7 @@ export async function lintWorkspaceRulesProjectGenerator(tree: Tree) {

await formatFiles(tree);

return jestInstallationTask;
return installTask;
}

export const lintWorkspaceRulesProjectSchematic = convertNxGenerator(
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {}
}
6 changes: 6 additions & 0 deletions packages/nx-plugin/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
"version": "11.0.17",
"description": "Update schema versions 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"
}
}
}
25 changes: 16 additions & 9 deletions packages/nx-plugin/src/generators/plugin/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import type { Tree } from '@nrwl/devkit';
import {
addDependenciesToPackageJson,
convertNxGenerator,
formatFiles,
generateFiles,
GeneratorCallback,
getWorkspaceLayout,
installPackagesTask,
joinPathFragments,
names,
normalizePath,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nrwl/devkit';
import type { Schema } from './schema';
import { nxVersion } from '../../utils/versions';
import * as path from 'path';
import { libraryGenerator } from '@nrwl/js';
import { addSwcDependencies } from '@nrwl/js/src/utils/swc/add-swc-dependencies';
import { swcNodeVersion } from 'nx/src/utils/versions';
import * as path from 'path';

import { nxVersion } from '../../utils/versions';
import { e2eProjectGenerator } from '../e2e-project/e2e';
import { generatorGenerator } from '../generator/generator';
import { executorGenerator } from '../executor/executor';
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
import { generatorGenerator } from '../generator/generator';

import type { Schema } from './schema';
interface NormalizedSchema extends Schema {
name: string;
fileName: string;
Expand Down Expand Up @@ -135,17 +138,21 @@ export async function pluginGenerator(host: Tree, schema: Schema) {

tasks.push(libraryTask);
AgentEnder marked this conversation as resolved.
Show resolved Hide resolved

const installTask = addDependenciesToPackageJson(
addDependenciesToPackageJson(
host,
{},
{
'@nrwl/devkit': nxVersion,
'@nrwl/jest': nxVersion,
'@nrwl/js': nxVersion,
'@swc-node/register': swcNodeVersion,
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);
updateWorkspaceJson(host, options);
Expand All @@ -160,7 +167,7 @@ export async function pluginGenerator(host: Tree, schema: Schema) {

await formatFiles(host);

return runTasksInSerial(...tasks);
return () => installPackagesTask(host);
}

export default pluginGenerator;
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
14 changes: 12 additions & 2 deletions packages/nx/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@
"homepage": "https://nx.dev",
"dependencies": {
"@parcel/watcher": "2.0.4",
"@swc-node/register": "^1.4.2",
"@swc/core": "^1.2.173",
"chalk": "4.1.0",
"chokidar": "^3.5.1",
"cli-cursor": "3.1.0",
Expand Down Expand Up @@ -61,6 +59,18 @@
"yargs": "^17.4.0",
"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": {
"migrations": "./migrations.json",
"packageGroup": [
Expand Down
107 changes: 96 additions & 11 deletions packages/nx/src/utils/register.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
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
Expand All @@ -7,22 +8,74 @@ import { join } from 'path';
* 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
* workspace path mapping will not, for example).
*
* @returns cleanup function
*/
export const registerTsProject = (
path: string,
configFilename = 'tsconfig.json'
) => {
// These are requires to prevent it from registering when it shouldn't
const { register } = require('@swc-node/register/register');
const {
readDefaultTsConfig,
} = require('@swc-node/register/read-default-tsconfig');
): (() => void) => {
const cleanupFunctions: (() => void)[] = [];

// Function to register transpiler that returns cleanup function
let registerTranspiler: () => () => void;

const tsConfigPath = join(path, configFilename);
cleanupFunctions.push(registerTsConfigPaths(tsConfigPath));
AgentEnder marked this conversation as resolved.
Show resolved Hide resolved

const swcNodeInstalled = packageIsInstalled('@swc-node/register');
if (swcNodeInstalled) {
// These are requires to prevent it from registering when it shouldn't
const { register } =
require('@swc-node/register/register') as typeof import('@swc-node/register/register');
const {
readDefaultTsConfig,
} = require('@swc-node/register/read-default-tsconfig');

try {
const tsConfigPath = join(path, configFilename);
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
*/
Expand All @@ -38,6 +91,38 @@ export const registerTsProject = (
paths: tsConfigResult.paths,
});
}
} catch (err) {}
} catch (err) {
warnNoTsconfigPaths();
}
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;
}
}
2 changes: 2 additions & 0 deletions packages/nx/src/utils/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ export const tslintVersion = '~6.1.0';
export const typescriptESLintVersion = '~5.18.0';
export const eslintVersion = '~8.12.0';
export const eslintConfigPrettierVersion = '8.1.0';
export const swcNodeVersion = '^1.4.2';
export const swcCoreVersion = '^1.2.173';