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

Jaybell/make buildable schematic #8916

Closed
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions docs/generated/api-workspace/generators/convert-to-buildable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
title: '@nrwl/workspace:convert-to-buildable generator'
description: 'Convert an Nx library to be buildable'
---

# @nrwl/workspace:convert-to-buildable

Convert an Nx library to be buildable

## Usage

```bash
nx generate convert-to-buildable ...
```

By default, Nx will search for `convert-to-buildable` in the default collection provisioned in `workspace.json`.

You can specify the collection explicitly as follows:

```bash
nx g @nrwl/workspace:convert-to-buildable ...
```

Show what will be generated without writing to disk:

```bash
nx g convert-to-buildable ... --dry-run
```

### Examples

Convert the my-feature-lib project to be buildable:

```bash
nx g @nrwl/workspace:convert-to-buildable --project my-feature-lib
```

## Options

### project

Type: `string`

Project name

### skipFormat

Default: `false`

Type: `boolean`

Skip formatting files.

### type

Type: `string`

Possible values: `js`, `node`, `nest`, `next`, `react`, `angular`, `detox`, `web`

The type of library that this is.
5 changes: 5 additions & 0 deletions docs/map.json
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,11 @@
"id": "convert-to-nx-project-generator",
"file": "generated/api-workspace/generators/convert-to-nx-project"
},
{
"name": "convert-to-buildable generator",
"id": "convert-to-buildable-generator",
"file": "generated/api-workspace/generators/convert-to-buildable"
},
{
"name": "run-commands executor",
"id": "run-commands-executor",
Expand Down
12 changes: 12 additions & 0 deletions packages/workspace/generators.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@
"description": "Moves a project's configuration outside of workspace.json"
},

"convert-to-buildable": {
"factory": "./src/generators/convert-to-buildable/convert-to-buildable#convertToBuildable",
"schema": "./src/generators/convert-to-buildable/schema.json",
"description": "Convert an Nx library to be buildable"
},

"npm-package": {
"factory": "./src/generators/npm-package/npm-package#npmPackageSchematic",
"schema": "./src/generators/npm-package/schema.json",
Expand Down Expand Up @@ -150,6 +156,12 @@
"description": "Moves a project's configuration outside of workspace.json"
},

"convert-to-buildable": {
"factory": "./src/generators/convert-to-buildable/convert-to-buildable#convertToBuildable",
"schema": "./src/generators/convert-to-buildable/schema.json",
"description": "Convert an Nx library to be buildable"
},

"npm-package": {
"factory": "./src/generators/npm-package/npm-package#npmPackageGenerator",
"schema": "./src/generators/npm-package/schema.json",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import {
getWorkspacePath,
isStandaloneProject,
NxJsonConfiguration,
readJsonFile,
readProjectConfiguration,
readWorkspaceConfiguration,
formatFiles,
Tree,
updateJson,
WorkspaceConfiguration,
writeJson,
convertNxGenerator,
} from '@nrwl/devkit';

import { Schema } from './schema';
import { checkWorkspaceVersion } from '@nrwl/workspace/src/utils/workspace';
import { join } from 'path';

function getExecutor(type: Schema['type']): string {
switch (type) {
case 'angular':
return '@nrwl/angular:ng-packagr-lite';
case 'detox':
case 'js':
case 'web':
return '@nrwl/js:tsc';
case 'next':
case 'react':
return '@nrwl/web:rollup';
case 'node':
case 'nest':
return '@nrwl/node:package';
}
}

export async function convertToBuildable(host: Tree, schema: Schema) {
const workspace = readWorkspaceConfiguration(host);

checkWorkspaceVersion(workspace, host);

const configuration = readProjectConfiguration(host, schema.project);

const nxJson = readJsonFile<NxJsonConfiguration>('nx.json');

if (configuration.targets['build'] != null) {
throw new Error(`${schema.project} is already buildable.`);
}
Comment on lines +39 to +41
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check makes sense if we keep going with only single-project command. So this isn't necessarily a change request, but rather a discussion point. Should we change this generator to take --all similar to how it works with the convert-to-nx-project generator? Should it be able to take a list of projects instead of only 1?

Since buildable libs can only depend on other buildable libs, I feel like the most common DX will be converting all libs that are in an apps dependency tree to buildable at the same time.

Copy link
Contributor Author

@yharaskrik yharaskrik Feb 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say yes we do want to be able to support that (and it's something I thought about while building this). Just a couple of things to consider:

  1. We would need to filter projects to only supported framework/type
  2. This Pr doesn't yet support Angular libs but that is handled by 1


/*
* Note on this: It seems new workspaces default to `packages` even though
* it is not set in nx.json whereas old workspaces may be using `libs` but
* it is also not set in the nx.json.
*/
const libDir = nxJson.workspaceLayout?.libsDir ?? 'packages';

const projectImport = `@${nxJson.npmScope}/${configuration.root.replace(
`${libDir}/`,
''
)}`;

const packageJson = readJsonFile('package.json');

// Write the package.json the builder will need
writeJson(host, join(configuration.root, 'package.json'), {
name: projectImport,
version: '0.0.1',
...(schema.type === 'angular'
? {
peerDependencies: {
'@angular/common': packageJson['dependencies']['@angular/common'],
'@angular/core': packageJson['dependencies']['@angular/core'],
},
dependencies: { tslib: packageJson['dependencies']['tslib'] },
}
: {}),
});

// Write the build target to the projects configuration
const buildTarget: any = {
executor: getExecutor(schema.type),
outputs: ['{options.outputPath}'],
options: {
outputPath: `dist/${configuration.root}`,
tsConfig: `${configuration.root}/tsconfig.lib.json`,
main: `${configuration.root}/src/index.ts`,
assets: [`${configuration.root}/*.md`],
},
};

switch (schema.type) {
case 'nest':
case 'node':
buildTarget.options['packageJson'] = `${configuration.root}/package.json`;
break;
case 'next':
case 'react':
const { main, ...options } = buildTarget.options;
buildTarget.options = {
...options,
project: `${configuration.root}/package.json`,
entryFile: `${configuration.root}/src/index.ts`,
external: ['react/jsx-runtime'],
rollupConfig: '@nrwl/react/plugins/bundle-rollup',
compiler: 'babel',
assets: [
{
glob: `${configuration.root}/README.md`,
input: '.',
output: '.',
},
],
};
break;
case 'angular':
buildTarget.options = {
project: `${configuration.root}/ng-package.json`,
};
buildTarget.outputs = [`dist/${configuration.root}`];
buildTarget.configurations = {
production: {
tsConfig: `${configuration.root}/tsconfig.lib.prod.json`,
},
development: {
tsConfig: `${configuration.root}/tsconfig.lib.json`,
},
};
buildTarget.defaultConfiguration = 'production';
break;
}

if (schema.type === 'angular') {
writeJson(host, join(configuration.root, 'tsconfig.lib.prod.json'), {
extends: './tsconfig.lib.json',
compilerOptions: {
declarationMap: false,
},
angularCompilerOptions: {},
});

writeJson(host, join(configuration.root, 'ng-package.json'), {
$schema: '../../node_modules/ng-packagr/ng-package.schema.json',
dest: `../../dist/${configuration.root}`,
lib: {
entryFile: 'src/index.ts',
},
});
}

const isStandalone = isStandaloneProject(host, schema.project);

if (isStandalone) {
writeJson(host, join(configuration.root, 'project.json'), {
...configuration,
targets: {
...configuration.targets,
build: buildTarget,
},
});
} else {
updateJson(host, getWorkspacePath(host), (value) => {
value.projects[schema.project].targets['build'] = buildTarget;
return value;
});
}

if (!schema.skipFormat) {
await formatFiles(host);
}
}

export default convertToBuildable;

export const convertToNxProjectSchematic =
convertNxGenerator(convertToBuildable);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface Schema {
project: string;
type: 'js' | 'node' | 'nest' | 'next' | 'react' | 'angular' | 'detox' | 'web';
skipFormat?: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "SchematicsConvertToBuildable",
"title": "Convert library to be a buildable lib",
"type": "object",
"cli": "nx",
"examples": [
{
"command": "g @nrwl/workspace:convert-to-buildable --project my-feature-lib",
"description": "Convert the my-feature-lib project to be buildable"
}
],
"properties": {
"project": {
"description": "Project name",
"type": "string"
},
"skipFormat": {
"description": "Skip formatting files.",
"type": "boolean",
"default": false
},
"type": {
"description": "The type of library that this is.",
"type": "string",
"enum": ["js", "node", "nest", "next", "react", "angular", "detox", "web"]
}
}
}
21 changes: 21 additions & 0 deletions packages/workspace/src/utils/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ import {
ProjectDefinition,
TargetDefinition,
} from '@angular-devkit/core/src/workspace';
import { logger } from '@nrwl/tao/src/shared/logger';
import {
getWorkspacePath,
WorkspaceConfiguration,
Tree as DevkitTree,
} from '@nrwl/devkit';

export function checkWorkspaceVersion(
workspace: WorkspaceConfiguration,
host: DevkitTree
) {
if (workspace.version < 2) {
logger.error(`
NX Only workspaces with version 2+ support project.json files.
To upgrade change the version number at the top of ${getWorkspacePath(
host
)} and run 'nx format'.
`);
throw new Error('v2+ Required');
}
}

function createHost(tree: Tree): workspaces.WorkspaceHost {
return {
Expand Down