Skip to content

Commit

Permalink
feat(js): inline non-buildable libs for tsc and swc
Browse files Browse the repository at this point in the history
  • Loading branch information
Chau Tran authored and Chau Tran committed Oct 3, 2022
1 parent 77b57b7 commit 284d2c1
Show file tree
Hide file tree
Showing 12 changed files with 538 additions and 16 deletions.
26 changes: 26 additions & 0 deletions docs/generated/packages/js.json
Expand Up @@ -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"],
Expand Down Expand Up @@ -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"],
Expand Down
66 changes: 66 additions & 0 deletions e2e/js/src/js.test.ts
@@ -1,3 +1,4 @@
import { execSync } from 'child_process';
import {
checkFilesDoNotExist,
checkFilesExist,
Expand Down Expand Up @@ -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(
Expand Down
3 changes: 1 addition & 2 deletions e2e/node/src/node.test.ts
Expand Up @@ -10,7 +10,6 @@ import {
packageInstall,
promisifiedTreeKill,
readFile,
removeFile,
runCLI,
runCLIAsync,
runCommandUntil,
Expand Down Expand Up @@ -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 = [
Expand Down
23 changes: 23 additions & 0 deletions packages/js/src/executors/swc/schema.json
Expand Up @@ -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"],
Expand Down
67 changes: 63 additions & 4 deletions packages/js/src/executors/swc/swc.impl.ts
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -67,6 +86,7 @@ export function normalizeOptions(
root: contextRoot,
sourceRoot,
projectRoot,
originalProjectRoot: projectRoot,
outputPath,
tsConfig: join(contextRoot, options.tsConfig),
swcCliOptions,
Expand Down Expand Up @@ -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());
Expand All @@ -113,6 +159,7 @@ export async function* swcExecutor(
},
context
);
removeTmpSwcrc(options.swcCliOptions.swcrcPath);
disposeFn = () => {
assetResult?.stop();
packageJsonResult?.stop();
Expand All @@ -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;
23 changes: 23 additions & 0 deletions packages/js/src/executors/tsc/schema.json
Expand Up @@ -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"],
Expand Down
2 changes: 1 addition & 1 deletion 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', () => {
Expand Down

0 comments on commit 284d2c1

Please sign in to comment.