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 all 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`

Name of project to convert to buildable lib.

### skipFormat

Default: `false`

Type: `boolean`

Skip formatting files.

### type

Type: `string`

Possible values: `js`, `node`, `nest`, `next`, `react`, `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#convertToBuildableSchematic",
"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,115 @@
import {
NxJsonConfiguration,
readJsonFile,
readProjectConfiguration,
formatFiles,
Tree,
writeJson,
convertNxGenerator,
updateProjectConfiguration,
} from '@nrwl/devkit';

import { Schema } from './schema';
import { join } from 'path';

function getExecutor(type: Schema['type']): string {
switch (type) {
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 configuration = readProjectConfiguration(host, schema.project);

yharaskrik marked this conversation as resolved.
Show resolved Hide resolved
if (configuration.projectType !== 'library') {
throw new Error(`${schema.project} is not a library.`);
}

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}/`,
''
)}`;

// Write the package.json the builder will need
writeJson(host, join(configuration.root, 'package.json'), {
name: projectImport,
version: '0.0.1',
});

// 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;
}

updateProjectConfiguration(host, schema.project, {
...configuration,
targets: {
...configuration.targets,
build: buildTarget,
},
});

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

export default convertToBuildable;

export const convertToBuildableSchematic =
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' | '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": "Name of project to convert to buildable lib.",
"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", "detox", "web"]
Copy link
Collaborator

@FrozenPandaz FrozenPandaz Feb 10, 2022

Choose a reason for hiding this comment

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

Ideally, I think this would be built into each package:

nx g @nrwl/js:library lib1 --buildable would be equivalent to say like nx g @nrwl/js:library lib1 && nx g @nrwl/js:add-build lib1

  1. Having a switch statement here effectively means you're writing 7 generators in 1
  2. You use these generators to add the target configuration to any project similar to how @nrwl/jest:jest-project adds a test target onto an existing project.
  3. @nrwl/react:add-build would inherit @nrwl/web:add-build
  4. We already have the logic in our library generators, and only need to extract it to be reusable.

We have 4 executors (3 in this PR + angular) so I think this would probably wind up being 4 executors?

We used this kind of strategy for convert-to-eslint.

What do you all think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah it might make more sense to have this split into each package. it would help keep like-minded code together, especially if we ever need to change how we create buildable libs and their config (e.g. angular might have to have some work done to the buildable lib implementation).

If the functionality to generate a buildable lib was extracted into a generator add-build that generator could just be reused in the library generator when --buildable is passed, as you suggested.

I like it, I think that makes more sense.

We could still have a generator in workspace package that will then call the underlying generators.

Copy link
Member

Choose a reason for hiding this comment

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

If we have these split into their respective packages, and have the root level 'add-buildable --all' option, how would it know run the generators? Should a generator in @nrwl/workspace rely on generators in other verticals? I wouldn't think so, but maybe dynamic imports would be a "good enough" way of doing them without adding deps to each plugin that supports buildable libs.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was thinking more along the lines of execSync(nx g ${packageName}:add-buildable)

}
}
}