diff --git a/docs/generated/packages/js.json b/docs/generated/packages/js.json index a18f28155a5a88..74efcabaaf7477 100644 --- a/docs/generated/packages/js.json +++ b/docs/generated/packages/js.json @@ -314,6 +314,19 @@ "description": "When `updateBuildableProjectDepsInPackageJson` is `true`, this adds dependencies to either `peerDependencies` or `dependencies`.", "enum": ["dependencies", "peerDependencies"], "default": "peerDependencies" + }, + "external": { + "description": "A list projects to be treated as external. This feature is experimental", + "oneOf": [ + { "type": "string", "enum": ["all", "none"] }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "externalBuildTargets": { + "type": "array", + "items": { "type": "string" }, + "description": "List of target names that annotate a build target for a project", + "default": ["build"] } }, "required": ["main", "outputPath", "tsConfig"], @@ -472,6 +485,19 @@ "description": "When `updateBuildableProjectDepsInPackageJson` is `true`, this adds dependencies to either `peerDependencies` or `dependencies`.", "enum": ["dependencies", "peerDependencies"], "default": "peerDependencies" + }, + "external": { + "description": "A list projects to be treated as external. This feature is experimental", + "oneOf": [ + { "type": "string", "enum": ["all", "none"] }, + { "type": "array", "items": { "type": "string" } } + ] + }, + "externalBuildTargets": { + "type": "array", + "items": { "type": "string" }, + "description": "List of target names that annotate a build target for a project", + "default": ["build"] } }, "required": ["main", "outputPath", "tsConfig"], diff --git a/e2e/js/src/js.test.ts b/e2e/js/src/js.test.ts index a0bc1eaf4cc8af..e683bcc56ab4a9 100644 --- a/e2e/js/src/js.test.ts +++ b/e2e/js/src/js.test.ts @@ -1,3 +1,4 @@ +import { execSync } from 'child_process'; import { checkFilesDoNotExist, checkFilesExist, @@ -303,6 +304,71 @@ export function ${lib}Wildcard() { ); }, 120000); + describe.only('inlining', () => { + it.each(['tsc', 'swc'])( + 'should inline libraries with --compiler=%s', + async (compiler) => { + const parent = uniq('parent'); + runCLI(`generate @nrwl/js:lib ${parent} --compiler=${compiler}`); + + const buildable = uniq('buildable'); + runCLI(`generate @nrwl/js:lib ${buildable}`); + + const nonBuildable = uniq('nonbuildable'); + runCLI(`generate @nrwl/js:lib ${nonBuildable} --buildable=false`); + + updateFile(`libs/${parent}/src/lib/${parent}.ts`, () => { + return ` +import { ${buildable} } from '@${scope}/${buildable}'; +import { ${nonBuildable} } from '@${scope}/${nonBuildable}'; + +export function ${parent}() { + ${buildable}(); + ${nonBuildable}(); +} + `; + }); + + // 1. external is set to all + execSync(`rm -rf dist`); + runCLI(`build ${parent} --external=all`); + checkFilesExist( + `dist/libs/${buildable}/src/index.js`, // buildable + `dist/libs/${parent}/src/index.js`, // parent + `dist/libs/${parent}/${nonBuildable}/src/index.js` // inlined non buildable + ); + // non-buildable lib import path is modified to relative path + let fileContent = readFile(`dist/libs/${parent}/src/lib/${parent}.js`); + expect(fileContent).toContain(`${nonBuildable}/src`); + + // 2. external is set to none + execSync(`rm -rf dist`); + runCLI(`build ${parent} --external=none`); + checkFilesExist( + `dist/libs/${parent}/src/index.js`, // parent + `dist/libs/${parent}/${buildable}/src/index.js`, // inlined buildable + `dist/libs/${parent}/${nonBuildable}/src/index.js` // inlined non buildable + ); + fileContent = readFile(`dist/libs/${parent}/src/lib/${parent}.js`); + expect(fileContent).toContain(`${nonBuildable}/src`); + expect(fileContent).toContain(`${buildable}/src`); + + // 3. external is set to an array of libs + execSync(`rm -rf dist`); + runCLI(`build ${parent} --external=${buildable}`); + checkFilesExist( + `dist/libs/${buildable}/src/index.js`, // buildable + `dist/libs/${parent}/src/index.js`, // parent + `dist/libs/${parent}/${nonBuildable}/src/index.js` // inlined non buildable + ); + fileContent = readFile(`dist/libs/${parent}/src/lib/${parent}.js`); + expect(fileContent).toContain(`${nonBuildable}/src`); + expect(fileContent).not.toContain(`${buildable}/src`); + }, + 120000 + ); + }); + it('should not create a `.babelrc` file when creating libs with js executors (--compiler=tsc)', () => { const lib = uniq('lib'); runCLI( diff --git a/e2e/node/src/node.test.ts b/e2e/node/src/node.test.ts index 710d8f5f6d990b..05984c1e58236e 100644 --- a/e2e/node/src/node.test.ts +++ b/e2e/node/src/node.test.ts @@ -10,7 +10,6 @@ import { packageInstall, promisifiedTreeKill, readFile, - removeFile, runCLI, runCLIAsync, runCommandUntil, @@ -485,7 +484,7 @@ describe('nest libraries', function () { const nestlib = uniq('nestlib'); runCLI(`generate @nrwl/nest:lib ${nestlib} --buildable`); - packageInstall('@nestjs/swagger', undefined, '~5.0.0'); + packageInstall('@nestjs/swagger', undefined, '~6.0.0'); updateProjectConfig(nestlib, (config) => { config.targets.build.options.transformers = [ diff --git a/packages/js/src/executors/swc/schema.json b/packages/js/src/executors/swc/schema.json index f6de3bc096fbe8..41d2482a9bed1b 100644 --- a/packages/js/src/executors/swc/schema.json +++ b/packages/js/src/executors/swc/schema.json @@ -72,6 +72,29 @@ "description": "When `updateBuildableProjectDepsInPackageJson` is `true`, this adds dependencies to either `peerDependencies` or `dependencies`.", "enum": ["dependencies", "peerDependencies"], "default": "peerDependencies" + }, + "external": { + "description": "A list projects to be treated as external. This feature is experimental", + "oneOf": [ + { + "type": "string", + "enum": ["all", "none"] + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "externalBuildTargets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of target names that annotate a build target for a project", + "default": ["build"] } }, "required": ["main", "outputPath", "tsConfig"], diff --git a/packages/js/src/executors/swc/swc.impl.ts b/packages/js/src/executors/swc/swc.impl.ts index 81fbd8858d1358..e4778280e2d028 100644 --- a/packages/js/src/executors/swc/swc.impl.ts +++ b/packages/js/src/executors/swc/swc.impl.ts @@ -3,21 +3,26 @@ import { assetGlobsToFiles, FileInputOutput, } from '@nrwl/workspace/src/utilities/assets'; -import { join, relative, resolve } from 'path'; - +import { removeSync } from 'fs-extra'; +import { dirname, join, relative, resolve } from 'path'; +import { copyAssets } from '../../utils/assets'; import { checkDependencies } from '../../utils/check-dependencies'; import { getHelperDependency, HelperDependency, } from '../../utils/compiler-helper-dependency'; +import { + handleInliningBuild, + postProcessInlinedDependencies, +} from '../../utils/inline'; +import { copyPackageJson } from '../../utils/package-json'; import { NormalizedSwcExecutorOptions, SwcExecutorOptions, } from '../../utils/schema'; import { compileSwc, compileSwcWatch } from '../../utils/swc/compile-swc'; import { getSwcrcPath } from '../../utils/swc/get-swcrc-path'; -import { copyAssets } from '../../utils/assets'; -import { copyPackageJson } from '../../utils/package-json'; +import { generateTmpSwcrc } from '../../utils/swc/inline'; export function normalizeOptions( options: SwcExecutorOptions, @@ -35,6 +40,20 @@ export function normalizeOptions( options.watch = false; } + // TODO: put back when inlining story is more stable + // if (options.external == null) { + // options.external = 'all'; + // } else if (Array.isArray(options.external) && options.external.length === 0) { + // options.external = 'none'; + // } + + if (Array.isArray(options.external) && options.external.length > 0) { + const firstItem = options.external[0]; + if (firstItem === 'all' || firstItem === 'none') { + options.external = firstItem; + } + } + const files: FileInputOutput[] = assetGlobsToFiles( options.assets, contextRoot, @@ -67,6 +86,7 @@ export function normalizeOptions( root: contextRoot, sourceRoot, projectRoot, + originalProjectRoot: projectRoot, outputPath, tsConfig: join(contextRoot, options.tsConfig), swcCliOptions, @@ -99,6 +119,32 @@ export async function* swcExecutor( dependencies.push(swcHelperDependency); } + const { inlinedDependencies, dependenciesToExclude } = handleInliningBuild( + context, + options, + options.tsConfig + ); + + if (inlinedDependencies.length > 0) { + options.projectRoot = '.'; // set to root of workspace to include other libs for type check + + // remap paths for SWC compilation + options.swcCliOptions.srcPath = options.swcCliOptions.swcCwd; + options.swcCliOptions.swcCwd = '.'; + options.swcCliOptions.destPath = options.swcCliOptions.destPath + .split('../') + .at(-1) + .concat('/', options.swcCliOptions.srcPath); + + // tmp swcrc with dependencies to exclude + // - buildable libraries + // - other libraries that are not dependent on the current project + options.swcCliOptions.swcrcPath = generateTmpSwcrc( + dependenciesToExclude, + options.swcCliOptions.swcrcPath + ); + } + if (options.watch) { let disposeFn: () => void; process.on('SIGINT', () => disposeFn()); @@ -113,6 +159,7 @@ export async function* swcExecutor( }, context ); + removeTmpSwcrc(options.swcCliOptions.swcrcPath); disposeFn = () => { assetResult?.stop(); packageJsonResult?.stop(); @@ -130,8 +177,20 @@ export async function* swcExecutor( }, context ); + removeTmpSwcrc(options.swcCliOptions.swcrcPath); + postProcessInlinedDependencies( + options.outputPath, + options.originalProjectRoot, + inlinedDependencies + ); }); } } +function removeTmpSwcrc(swcrcPath: string) { + if (swcrcPath.startsWith('tmp/')) { + removeSync(dirname(swcrcPath)); + } +} + export default swcExecutor; diff --git a/packages/js/src/executors/tsc/schema.json b/packages/js/src/executors/tsc/schema.json index c1a8695c686542..a1876e59f97d45 100644 --- a/packages/js/src/executors/tsc/schema.json +++ b/packages/js/src/executors/tsc/schema.json @@ -61,6 +61,29 @@ "description": "When `updateBuildableProjectDepsInPackageJson` is `true`, this adds dependencies to either `peerDependencies` or `dependencies`.", "enum": ["dependencies", "peerDependencies"], "default": "peerDependencies" + }, + "external": { + "description": "A list projects to be treated as external. This feature is experimental", + "oneOf": [ + { + "type": "string", + "enum": ["all", "none"] + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "externalBuildTargets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of target names that annotate a build target for a project", + "default": ["build"] } }, "required": ["main", "outputPath", "tsConfig"], diff --git a/packages/js/src/executors/tsc/tsc.impl.spec.ts b/packages/js/src/executors/tsc/tsc.impl.spec.ts index 7f390baa33e639..c6ecb2ee13b9cf 100644 --- a/packages/js/src/executors/tsc/tsc.impl.spec.ts +++ b/packages/js/src/executors/tsc/tsc.impl.spec.ts @@ -1,8 +1,8 @@ import { ExecutorContext } from '@nrwl/devkit'; import { ExecutorOptions } from '../../utils/schema'; import { - normalizeOptions, createTypeScriptCompilationOptions, + normalizeOptions, } from './tsc.impl'; describe('tscExecutor', () => { diff --git a/packages/js/src/executors/tsc/tsc.impl.ts b/packages/js/src/executors/tsc/tsc.impl.ts index c84cf908ca2d23..b9bcc30e6fceec 100644 --- a/packages/js/src/executors/tsc/tsc.impl.ts +++ b/packages/js/src/executors/tsc/tsc.impl.ts @@ -3,7 +3,7 @@ import { assetGlobsToFiles, FileInputOutput, } from '@nrwl/workspace/src/utilities/assets'; -import { TypeScriptCompilationOptions } from '@nrwl/workspace/src/utilities/typescript/compilation'; +import type { TypeScriptCompilationOptions } from '@nrwl/workspace/src/utilities/typescript/compilation'; import { join, resolve } from 'path'; import { CustomTransformers, @@ -11,16 +11,20 @@ import { SourceFile, TransformerFactory, } from 'typescript'; +import { CopyAssetsHandler } from '../../utils/assets/copy-assets-handler'; import { checkDependencies } from '../../utils/check-dependencies'; import { getHelperDependency, HelperDependency, } from '../../utils/compiler-helper-dependency'; -import { CopyAssetsHandler } from '../../utils/assets/copy-assets-handler'; +import { + handleInliningBuild, + postProcessInlinedDependencies, +} from '../../utils/inline'; +import { updatePackageJson } from '../../utils/package-json/update-package-json'; import { ExecutorOptions, NormalizedExecutorOptions } from '../../utils/schema'; import { compileTypeScriptFiles } from '../../utils/typescript/compile-typescript-files'; import { loadTsTransformers } from '../../utils/typescript/load-ts-transformers'; -import { updatePackageJson } from '../../utils/package-json/update-package-json'; import { watchForSingleFileChanges } from '../../utils/watch-for-single-file-changes'; export function normalizeOptions( @@ -38,6 +42,20 @@ export function normalizeOptions( options.watch = false; } + // TODO: put back when inlining story is more stable + // if (options.external == null) { + // options.external = 'all'; + // } else if (Array.isArray(options.external) && options.external.length === 0) { + // options.external = 'none'; + // } + + if (Array.isArray(options.external) && options.external.length > 0) { + const firstItem = options.external[0]; + if (firstItem === 'all' || firstItem === 'none') { + options.external = firstItem; + } + } + const files: FileInputOutput[] = assetGlobsToFiles( options.assets, contextRoot, @@ -141,12 +159,32 @@ export async function* tscExecutor( process.on('SIGTERM', () => handleTermination()); } + const tsCompilationOptions = createTypeScriptCompilationOptions( + options, + context + ); + + const { inlinedDependencies } = handleInliningBuild( + context, + options, + tsCompilationOptions.tsConfig + ); + + if (inlinedDependencies.length > 0) { + tsCompilationOptions.rootDir = '.'; + } + return yield* compileTypeScriptFiles( options, - createTypeScriptCompilationOptions(options, context), + tsCompilationOptions, async () => { await assetHandler.processAllAssetsOnce(); updatePackageJson(options, context, target, dependencies); + postProcessInlinedDependencies( + tsCompilationOptions.outputPath, + tsCompilationOptions.projectRoot, + inlinedDependencies + ); } ); } diff --git a/packages/js/src/utils/inline.ts b/packages/js/src/utils/inline.ts new file mode 100644 index 00000000000000..713913da622979 --- /dev/null +++ b/packages/js/src/utils/inline.ts @@ -0,0 +1,266 @@ +import type { + ExecutorContext, + ProjectGraphDependency, + ProjectGraphProjectNode, +} from '@nrwl/devkit'; +import { readJsonFile } from '@nrwl/devkit'; +import { + copySync, + readdirSync, + readFileSync, + removeSync, + writeFileSync, +} from 'fs-extra'; +import { join, relative } from 'path'; +import type { NormalizedExecutorOptions } from './schema'; + +export interface InlinedProjectNode extends ProjectGraphProjectNode { + pathAlias: string; + buildOutputPath?: string; +} + +export function handleInliningBuild( + context: ExecutorContext, + options: NormalizedExecutorOptions, + tsConfigPath: string +): Record< + 'inlinedDependencies' | 'dependenciesToExclude', + InlinedProjectNode[] +> { + if (options.external == null) { + return { inlinedDependencies: [], dependenciesToExclude: [] }; + } + + const projectDependencies = + context.projectGraph.dependencies[context.projectName] || []; + const implicitDependencies = + context.projectGraph.nodes[context.projectName].data.implicitDependencies || + []; + const tsConfigJson = readJsonFile(tsConfigPath); + + const externalNodes = getExternalNodes( + context, + projectDependencies, + implicitDependencies, + tsConfigJson['compilerOptions']['paths'] || {} + ); + const inlinedDependencies: Array<{ + name: string; + path: string; + buildOutputPath: string; + }> = []; + const buildableDependencies: Array<{ name: string; path: string }> = []; + + if (projectDependencies && projectDependencies.length) { + // handle inlining + // 1. figure out a list of dependencies that need to be inlined + for (const projectDependency of projectDependencies) { + // skip npm packages + if (projectDependency.target.startsWith('npm')) { + continue; + } + + // skip implicitDependencies + if (implicitDependencies.includes(projectDependency.target)) { + continue; + } + + const pathAlias = getPathAliasForPackage( + context.projectGraph.nodes[projectDependency.target], + tsConfigJson['compilerOptions']['paths'] + ); + + const buildOutputPath = getBuildOutputPath( + projectDependency.target, + context, + options + ); + + const shouldInline = + /** + * if all buildable libraries are marked as external, + * then push the project dependency that doesn't have a build target + */ + (options.external === 'all' && !buildOutputPath) || + /** + * if all buildable libraries are marked as internal, + * then push every project dependency to be inlined + */ + options.external === 'none' || + /** + * if some buildable libraries are marked as external, + * then push the project dependency that IS NOT marked as external OR doesn't have a build target + */ + (Array.isArray(options.external) && + options.external.length > 0 && + !options.external.includes(projectDependency.target)) || + !buildOutputPath; + + if (shouldInline) { + inlinedDependencies.push({ + name: projectDependency.target, + path: pathAlias, + buildOutputPath, + }); + } + + if (buildOutputPath) { + buildableDependencies.push({ + name: projectDependency.target, + path: pathAlias, + }); + } + } + } + + return { + inlinedDependencies: inlinedDependencies.map((dep) => ({ + ...context.projectGraph.nodes[dep.name], + pathAlias: dep.path, + buildOutputPath: dep.buildOutputPath, + })), + dependenciesToExclude: [ + ...buildableDependencies.map((dep) => ({ + ...context.projectGraph.nodes[dep.name], + pathAlias: dep.path, + })), + ...externalNodes, + ], + }; +} + +export function postProcessInlinedDependencies( + outputPath: string, + parentOutputPath: string, + inlinedDependencies: InlinedProjectNode[] +) { + if (inlinedDependencies.length === 0) { + return; + } + + const parentDistPath = join(outputPath, parentOutputPath); + + // move parentOutput + movePackage(parentDistPath, outputPath); + + const inlinedDepsDestOutputRecord: Record = {}; + // move inlined outputs + for (const inlinedDependency of inlinedDependencies) { + const depOutputPath = + inlinedDependency.buildOutputPath || + join(outputPath, inlinedDependency.data.root); + const destDepOutputPath = join(outputPath, inlinedDependency.name); + movePackage(depOutputPath, destDepOutputPath); + + // TODO: hard-coded "src" + // use double quote so it matches the whole string + // when we build the Regex later + inlinedDepsDestOutputRecord[`"${inlinedDependency.pathAlias}"`] = + destDepOutputPath + '/src'; + } + + updateImports(outputPath, inlinedDepsDestOutputRecord); +} + +function getExternalNodes( + context: ExecutorContext, + projectDependencies: ProjectGraphDependency[], + implicitDependencies: string[], + pathAliases: Record +): InlinedProjectNode[] { + return Object.keys(context.projectGraph.nodes) + .filter( + (nodeName) => + projectDependencies.every((dep) => dep.target !== nodeName) && + implicitDependencies.every((dep) => dep !== nodeName) && + nodeName !== context.projectName + ) + .map((nodeName) => ({ + ...context.projectGraph.nodes[nodeName], + pathAlias: getPathAliasForPackage( + context.projectGraph.nodes[nodeName], + pathAliases + ), + })); +} + +export function movePackage(from: string, to: string) { + copySync(from, to, { overwrite: true, recursive: true }); + removeSync(from); +} + +function updateImports( + destOutputPath: string, + inlinedDepsDestOutputRecord: Record +) { + const importRegex = new RegExp( + Object.keys(inlinedDepsDestOutputRecord).join('|'), + 'g' + ); + recursiveUpdateImport( + destOutputPath + '/src', + importRegex, + inlinedDepsDestOutputRecord + ); +} + +function recursiveUpdateImport( + dirPath: string, + importRegex: RegExp, + inlinedDepsDestOutputRecord: Record +) { + const files = readdirSync(dirPath, { withFileTypes: true }); + for (const file of files) { + // only check .js and .d.ts files + if ( + file.isFile() && + (file.name.endsWith('.js') || file.name.endsWith('.d.ts')) + ) { + const filePath = join(dirPath, file.name); + const fileContent = readFileSync(filePath, 'utf-8'); + const updatedContent = fileContent.replace( + importRegex, + (matched) => + `"${relative(dirPath, inlinedDepsDestOutputRecord[matched])}"` + ); + writeFileSync(filePath, updatedContent); + } else if (file.isDirectory()) { + recursiveUpdateImport( + join(dirPath, file.name), + importRegex, + inlinedDepsDestOutputRecord + ); + } + } +} + +function getPathAliasForPackage( + packageNode: ProjectGraphProjectNode, + pathAliases: Record +): string { + if (!packageNode) return ''; + + for (const [alias, paths] of Object.entries(pathAliases)) { + if (paths.some((path) => path.includes(packageNode.data.root))) { + return alias; + } + } + + return ''; +} + +function getBuildOutputPath( + projectName: string, + context: ExecutorContext, + options: NormalizedExecutorOptions +): string { + const buildTarget = options.externalBuildTargets.find( + (buildTarget) => + context.projectGraph.nodes[projectName]?.data?.targets?.[buildTarget] + ); + + if (buildTarget) + return context.projectGraph.nodes[projectName].data.targets?.[buildTarget] + .options['outputPath']; + return ''; +} diff --git a/packages/js/src/utils/schema.d.ts b/packages/js/src/utils/schema.d.ts index 239a3aeccf2715..3f1a9003e16cef 100644 --- a/packages/js/src/utils/schema.d.ts +++ b/packages/js/src/utils/schema.d.ts @@ -45,6 +45,8 @@ export interface ExecutorOptions { transformers: TransformerEntry[]; updateBuildableProjectDepsInPackageJson?: boolean; buildableProjectDepsInPackageJsonType?: 'dependencies' | 'peerDependencies'; + external?: 'all' | 'none' | string[]; + externalBuildTargets?: string[]; } export interface NormalizedExecutorOptions extends ExecutorOptions { @@ -72,6 +74,7 @@ export interface SwcCliOptions { export interface NormalizedSwcExecutorOptions extends NormalizedExecutorOptions { + originalProjectRoot: string; swcExclude: string[]; skipTypeCheck: boolean; swcCliOptions: SwcCliOptions; diff --git a/packages/js/src/utils/swc/compile-swc.ts b/packages/js/src/utils/swc/compile-swc.ts index 51b2a2cedc43f8..324588f76d33d4 100644 --- a/packages/js/src/utils/swc/compile-swc.ts +++ b/packages/js/src/utils/swc/compile-swc.ts @@ -1,11 +1,10 @@ -import { ExecutorContext, logger } from '@nrwl/devkit'; +import { cacheDir, ExecutorContext, logger } from '@nrwl/devkit'; import { exec, execSync } from 'child_process'; -import { cacheDir } from '@nrwl/devkit'; +import { removeSync } from 'fs-extra'; import { createAsyncIterable } from '../create-async-iterable/create-async-iteratable'; import { NormalizedSwcExecutorOptions, SwcCliOptions } from '../schema'; import { printDiagnostics } from '../typescript/print-diagnostics'; import { runTypeCheck, TypeCheckOptions } from '../typescript/run-type-check'; -import { removeSync } from 'fs-extra'; function getSwcCmd( { swcrcPath, srcPath, destPath }: SwcCliOptions, @@ -51,9 +50,8 @@ export async function compileSwc( logger.log(swcCmdLog.replace(/\n/, '')); const isCompileSuccess = swcCmdLog.includes('Successfully compiled'); - await postCompilationCallback(); - if (normalizedOptions.skipTypeCheck) { + await postCompilationCallback(); return { success: isCompileSuccess }; } @@ -67,6 +65,7 @@ export async function compileSwc( await printDiagnostics(errors, warnings); } + await postCompilationCallback(); return { success: !hasErrors && isCompileSuccess }; } diff --git a/packages/js/src/utils/swc/inline.ts b/packages/js/src/utils/swc/inline.ts new file mode 100644 index 00000000000000..ef952c14a74238 --- /dev/null +++ b/packages/js/src/utils/swc/inline.ts @@ -0,0 +1,20 @@ +import { readJsonFile, writeJsonFile } from '@nrwl/devkit'; +import type { InlinedProjectNode } from '../inline'; + +export function generateTmpSwcrc( + buildableDependencies: InlinedProjectNode[], + swcrcPath: string +) { + const swcrc = readJsonFile(swcrcPath); + + swcrc['exclude'] = swcrc['exclude'].concat( + '.*.d.ts$', + buildableDependencies.map((dep) => `${dep.data.root}/**/.*.ts$`), + 'node_modules/**/*.ts$' + ); + + const tmpSwcrcPath = `tmp/${swcrcPath}`; + writeJsonFile(tmpSwcrcPath, swcrc); + + return tmpSwcrcPath; +}