diff --git a/.circleci/config.yml b/.circleci/config.yml index e3245cab97..4879a22cc1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ var_2: 'e2e-cli,e2e-nx-plugin,dep-graph-client-e2e', 'e2e-cypress,e2e-jest', 'e2e-react', - 'e2e-next', + 'e2e-next,e2e-gatsby', 'e2e-node', 'e2e-web,e2e-linter,e2e-storybook', ] diff --git a/.cz-config.js b/.cz-config.js index 6825222772..ab5dc56b50 100644 --- a/.cz-config.js +++ b/.cz-config.js @@ -19,6 +19,7 @@ module.exports = { { name: 'core', description: 'anything Nx core specific' }, { name: 'nxdev', description: 'anything related to docs infrastructure' }, { name: 'nextjs', description: 'anything Next specific' }, + { name: 'gatsby', description: 'anything Gatsby specific' }, { name: 'nest', description: 'anything Nest specific' }, { name: 'node', description: 'anything Node specific' }, { name: 'express', description: 'anything Express specific' }, diff --git a/docs/angular/api-gatsby/executors/build.md b/docs/angular/api-gatsby/executors/build.md new file mode 100644 index 0000000000..1e7af3c170 --- /dev/null +++ b/docs/angular/api-gatsby/executors/build.md @@ -0,0 +1,47 @@ +# build + +Build a Gatsby app + +Properties can be configured in angular.json when defining the executor, or when invoking it. + +## Properties + +### color + +Default: `true` + +Type: `boolean` + +Enable colored terminal output. + +### graphqlTracing + +Type: `boolean` + +Trace every graphql resolver, may have performance implications. + +### openTracingConfigFile + +Type: `string` + +Tracer configuration file (OpenTracing compatible). + +### prefixPaths + +Type: `boolean` + +Build site with link paths prefixed (set pathPrefix in your config). + +### profile + +Type: `boolean` + +Build site with react profiling. + +### uglify + +Default: `true` + +Type: `boolean` + +Build site without uglifying JS bundles (true by default). diff --git a/docs/angular/api-gatsby/executors/server.md b/docs/angular/api-gatsby/executors/server.md new file mode 100644 index 0000000000..9fea830c4d --- /dev/null +++ b/docs/angular/api-gatsby/executors/server.md @@ -0,0 +1,43 @@ +# server + +Starts server for app + +Properties can be configured in angular.json when defining the executor, or when invoking it. + +## Properties + +### buildTarget + +Type: `string` + +Target which builds the application + +### host + +Default: `localhost` + +Type: `string` + +Host to listen on. + +### https + +Default: `false` + +Type: `boolean` + +Serve using HTTPS. + +### open + +Type: `boolean` + +Open the site in your (default) browser for you. + +### port + +Default: `4200` + +Type: `number` + +Port to listen on. diff --git a/docs/angular/api-gatsby/generators/application.md b/docs/angular/api-gatsby/generators/application.md new file mode 100644 index 0000000000..6378fe7a59 --- /dev/null +++ b/docs/angular/api-gatsby/generators/application.md @@ -0,0 +1,89 @@ +# application + +Create an application + +## Usage + +```bash +nx generate application ... +``` + +```bash +nx g app ... # same +``` + +By default, Nx will search for `application` in the default collection provisioned in `angular.json`. + +You can specify the collection explicitly as follows: + +```bash +nx g @nrwl/gatsby:application ... +``` + +Show what will be generated without writing to disk: + +```bash +nx g application ... --dry-run +``` + +## Options + +### directory + +Alias(es): d + +Type: `string` + +A directory where the project is placed + +### e2eTestRunner + +Default: `cypress` + +Type: `string` + +Possible values: `cypress`, `none` + +Adds the specified e2e test runner + +### js + +Default: `false` + +Type: `boolean` + +Generate JavaScript files rather than TypeScript files + +### name + +Type: `string` + +### style + +Alias(es): s + +Default: `css` + +Type: `string` + +Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/styled`, `none` + +The file extension to be used for style files. + +### tags + +Alias(es): t + +Type: `string` + +Add tags to the project (used for linting) + +### unitTestRunner + +Default: `jest` + +Type: `string` + +Possible values: `jest`, `none` + +Adds the specified unit test runner diff --git a/docs/angular/api-gatsby/generators/component.md b/docs/angular/api-gatsby/generators/component.md new file mode 100644 index 0000000000..58421410b8 --- /dev/null +++ b/docs/angular/api-gatsby/generators/component.md @@ -0,0 +1,107 @@ +# component + +Create a component + +## Usage + +```bash +nx generate component ... +``` + +By default, Nx will search for `component` in the default collection provisioned in `angular.json`. + +You can specify the collection explicitly as follows: + +```bash +nx g @nrwl/gatsby:component ... +``` + +Show what will be generated without writing to disk: + +```bash +nx g component ... --dry-run +``` + +### Examples + +Generate a component in the mylib library: + +```bash +nx g component my-component --project=mylib +``` + +Generate a class component in the mylib library: + +```bash +nx g component my-component --project=mylib --classComponent +``` + +## Options + +### directory + +Alias(es): d + +Type: `string` + +Create the component under this directory (can be nested). + +### export + +Alias(es): e + +Default: `false` + +Type: `boolean` + +When true, the component is exported from the project index.ts (if it exists). + +### flat + +Default: `false` + +Type: `boolean` + +Create component at the source root rather than its own directory. + +### js + +Default: `false` + +Type: `boolean` + +Generate JavaScript files rather than TypeScript files. + +### name + +Type: `string` + +The name of the component. + +### project + +Alias(es): p + +Type: `string` + +The name of the project. + +### skipTests + +Default: `false` + +Type: `boolean` + +When true, does not create "spec.ts" test files for the new component. + +### style + +Alias(es): s + +Default: `css` + +Type: `string` + +Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/styled`, `none` + +The file extension to be used for style files. diff --git a/docs/angular/api-gatsby/generators/page.md b/docs/angular/api-gatsby/generators/page.md new file mode 100644 index 0000000000..f188dae08d --- /dev/null +++ b/docs/angular/api-gatsby/generators/page.md @@ -0,0 +1,107 @@ +# page + +Create a page + +## Usage + +```bash +nx generate page ... +``` + +By default, Nx will search for `page` in the default collection provisioned in `angular.json`. + +You can specify the collection explicitly as follows: + +```bash +nx g @nrwl/gatsby:page ... +``` + +Show what will be generated without writing to disk: + +```bash +nx g page ... --dry-run +``` + +### Examples + +Generate a page in the mylib library: + +```bash +nx g page my-page --project=mylib +``` + +Generate a class component in the mylib library: + +```bash +nx g page my-page --project=mylib --classComponent +``` + +## Options + +### directory + +Alias(es): d + +Type: `string` + +Create the component under this directory (can be nested). + +### export + +Alias(es): e + +Default: `false` + +Type: `boolean` + +When true, the component is exported from the project index.ts (if it exists). + +### flat + +Default: `false` + +Type: `boolean` + +Create component at the source root rather than its own directory. + +### js + +Default: `false` + +Type: `boolean` + +Generate JavaScript files rather than TypeScript files. + +### name + +Type: `string` + +The name of the component. + +### project + +Alias(es): p + +Type: `string` + +The name of the project. + +### skipTests + +Default: `false` + +Type: `boolean` + +When true, does not create "spec.ts" test files for the new component. + +### style + +Alias(es): s + +Default: `css` + +Type: `string` + +Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/styled`, `none` + +The file extension to be used for style files. diff --git a/docs/angular/executors.json b/docs/angular/executors.json index 722846ec08..ded073647f 100644 --- a/docs/angular/executors.json +++ b/docs/angular/executors.json @@ -2,6 +2,7 @@ "angular", "cypress", "express", + "gatsby", "jest", "linter", "nest", diff --git a/docs/angular/generators.json b/docs/angular/generators.json index ae621ac6e8..46a738dc38 100644 --- a/docs/angular/generators.json +++ b/docs/angular/generators.json @@ -2,6 +2,7 @@ "angular", "cypress", "express", + "gatsby", "jest", "nest", "next", diff --git a/docs/map.json b/docs/map.json index 818298eb1d..874923506c 100644 --- a/docs/map.json +++ b/docs/map.json @@ -1699,6 +1699,104 @@ "name": "service generator", "id": "service", "file": "react/api-nest/generators/service" + }, + { + "name": "gatsby", + "id": "gatsby", + "itemList": [ + { + "id": "overview", + "name": "Overview", + "searchResultsName": "@nrwl/gatsby Overview", + "file": "shared/gatsby-plugin" + }, + { + "id": "generators", + "name": "Generators", + "itemList": [ + { + "name": "application", + "id": "application", + "file": "angular/api-gatsby/generators/application" + }, + { + "name": "component", + "id": "component", + "file": "angular/api-gatsby/generators/component" + }, + { + "name": "page", + "id": "page", + "file": "angular/api-gatsby/generators/page" + } + ] + }, + { + "id": "executors", + "name": "Executors / Builders", + "itemList": [ + { + "name": "build", + "id": "build", + "file": "angular/api-gatsby/executors/build" + }, + { + "name": "server", + "id": "server", + "file": "angular/api-gatsby/executors/server" + } + ] + } + ] + }, + { + "name": "Nx Plugin", + "id": "nx-plugin", + "itemList": [ + { + "id": "overview", + "name": "Overview", + "searchResultsName": "@nrwl/nx-plugin Overview", + "file": "shared/nx-plugin" + }, + { + "id": "generators", + "name": "Generators", + "itemList": [ + { + "name": "executor", + "id": "executor", + "file": "angular/api-nx-plugin/generators/executor" + }, + { + "name": "migration", + "id": "migration", + "file": "angular/api-nx-plugin/generators/migration" + }, + { + "name": "plugin", + "id": "plugin", + "file": "angular/api-nx-plugin/generators/plugin" + }, + { + "name": "generator", + "id": "schematic", + "file": "angular/api-nx-plugin/generators/generator" + } + ] + }, + { + "id": "executors", + "name": "Executors / Builders", + "itemList": [ + { + "name": "e2e", + "id": "e2e", + "file": "angular/api-nx-plugin/executors/e2e" + } + ] + } + ] } ] }, @@ -2229,6 +2327,104 @@ "name": "run-commands executor", "id": "run-commands", "file": "node/api-workspace/executors/run-commands" + }, + { + "name": "gatsby", + "id": "gatsby", + "itemList": [ + { + "id": "overview", + "name": "Overview", + "searchResultsName": "@nrwl/gatsby Overview", + "file": "shared/gatsby-plugin" + }, + { + "id": "generators", + "name": "Generators", + "itemList": [ + { + "name": "application", + "id": "application", + "file": "react/api-gatsby/generators/application" + }, + { + "name": "component", + "id": "component", + "file": "react/api-gatsby/generators/component" + }, + { + "name": "page", + "id": "page", + "file": "react/api-gatsby/generators/page" + } + ] + }, + { + "id": "executors", + "name": "Executors / Builders", + "itemList": [ + { + "name": "build", + "id": "build", + "file": "react/api-gatsby/executors/build" + }, + { + "name": "server", + "id": "server", + "file": "react/api-gatsby/executors/server" + } + ] + } + ] + }, + { + "name": "Nx Plugin", + "id": "nx-plugin", + "itemList": [ + { + "id": "overview", + "name": "Overview", + "searchResultsName": "@nrwl/nx-plugin Overview", + "file": "shared/nx-plugin" + }, + { + "id": "generators", + "name": "Generators", + "itemList": [ + { + "name": "executor", + "id": "executor", + "file": "react/api-nx-plugin/generators/executor" + }, + { + "name": "migration", + "id": "migration", + "file": "react/api-nx-plugin/generators/migration" + }, + { + "name": "plugin", + "id": "plugin", + "file": "react/api-nx-plugin/generators/plugin" + }, + { + "name": "generator", + "id": "schematic", + "file": "react/api-nx-plugin/generators/generator" + } + ] + }, + { + "id": "executors", + "name": "Executors / Builders", + "itemList": [ + { + "name": "e2e", + "id": "e2e", + "file": "react/api-nx-plugin/executors/e2e" + } + ] + } + ] } ] }, @@ -2769,6 +2965,104 @@ "name": "Dependency Graph", "id": "dependency-graph", "file": "shared/workspace/structure/dependency-graph" + }, + { + "name": "gatsby", + "id": "gatsby", + "itemList": [ + { + "id": "overview", + "name": "Overview", + "searchResultsName": "@nrwl/gatsby Overview", + "file": "shared/gatsby-plugin" + }, + { + "id": "generators", + "name": "Generators", + "itemList": [ + { + "name": "application", + "id": "application", + "file": "node/api-gatsby/generators/application" + }, + { + "name": "component", + "id": "component", + "file": "node/api-gatsby/generators/component" + }, + { + "name": "page", + "id": "page", + "file": "node/api-gatsby/generators/page" + } + ] + }, + { + "id": "executors", + "name": "Executors / Builders", + "itemList": [ + { + "name": "build", + "id": "build", + "file": "node/api-gatsby/executors/build" + }, + { + "name": "server", + "id": "server", + "file": "node/api-gatsby/executors/server" + } + ] + } + ] + }, + { + "name": "Nx Plugin", + "id": "nx-plugin", + "itemList": [ + { + "id": "overview", + "name": "Overview", + "searchResultsName": "@nrwl/nx-plugin Overview", + "file": "shared/nx-plugin" + }, + { + "id": "generators", + "name": "Generators", + "itemList": [ + { + "name": "executor", + "id": "executor", + "file": "node/api-nx-plugin/generators/executor" + }, + { + "name": "migration", + "id": "migration", + "file": "node/api-nx-plugin/generators/migration" + }, + { + "name": "plugin", + "id": "plugin", + "file": "node/api-nx-plugin/generators/plugin" + }, + { + "name": "generator", + "id": "schematic", + "file": "node/api-nx-plugin/generators/generator" + } + ] + }, + { + "id": "executors", + "name": "Executors / Builders", + "itemList": [ + { + "name": "e2e", + "id": "e2e", + "file": "node/api-nx-plugin/executors/e2e" + } + ] + } + ] } ] }, diff --git a/docs/node/api-gatsby/executors/build.md b/docs/node/api-gatsby/executors/build.md new file mode 100644 index 0000000000..cfb459a584 --- /dev/null +++ b/docs/node/api-gatsby/executors/build.md @@ -0,0 +1,48 @@ +# build + +Build a Gatsby app + +Properties can be configured in workspace.json when defining the executor, or when invoking it. +Read more about how to use executors and the CLI here: https://nx.dev/node/guides/cli. + +## Properties + +### color + +Default: `true` + +Type: `boolean` + +Enable colored terminal output. + +### graphqlTracing + +Type: `boolean` + +Trace every graphql resolver, may have performance implications. + +### openTracingConfigFile + +Type: `string` + +Tracer configuration file (OpenTracing compatible). + +### prefixPaths + +Type: `boolean` + +Build site with link paths prefixed (set pathPrefix in your config). + +### profile + +Type: `boolean` + +Build site with react profiling. + +### uglify + +Default: `true` + +Type: `boolean` + +Build site without uglifying JS bundles (true by default). diff --git a/docs/node/api-gatsby/executors/server.md b/docs/node/api-gatsby/executors/server.md new file mode 100644 index 0000000000..7dcf9531e6 --- /dev/null +++ b/docs/node/api-gatsby/executors/server.md @@ -0,0 +1,44 @@ +# server + +Starts server for app + +Properties can be configured in workspace.json when defining the executor, or when invoking it. +Read more about how to use executors and the CLI here: https://nx.dev/node/guides/cli. + +## Properties + +### buildTarget + +Type: `string` + +Target which builds the application + +### host + +Default: `localhost` + +Type: `string` + +Host to listen on. + +### https + +Default: `false` + +Type: `boolean` + +Serve using HTTPS. + +### open + +Type: `boolean` + +Open the site in your (default) browser for you. + +### port + +Default: `4200` + +Type: `number` + +Port to listen on. diff --git a/docs/node/api-gatsby/generators/application.md b/docs/node/api-gatsby/generators/application.md new file mode 100644 index 0000000000..444d19ee1b --- /dev/null +++ b/docs/node/api-gatsby/generators/application.md @@ -0,0 +1,89 @@ +# application + +Create an application + +## Usage + +```bash +nx generate application ... +``` + +```bash +nx g app ... # same +``` + +By default, Nx will search for `application` in the default collection provisioned in `workspace.json`. + +You can specify the collection explicitly as follows: + +```bash +nx g @nrwl/gatsby:application ... +``` + +Show what will be generated without writing to disk: + +```bash +nx g application ... --dry-run +``` + +## Options + +### directory + +Alias(es): d + +Type: `string` + +A directory where the project is placed + +### e2eTestRunner + +Default: `cypress` + +Type: `string` + +Possible values: `cypress`, `none` + +Adds the specified e2e test runner + +### js + +Default: `false` + +Type: `boolean` + +Generate JavaScript files rather than TypeScript files + +### name + +Type: `string` + +### style + +Alias(es): s + +Default: `css` + +Type: `string` + +Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/styled`, `none` + +The file extension to be used for style files. + +### tags + +Alias(es): t + +Type: `string` + +Add tags to the project (used for linting) + +### unitTestRunner + +Default: `jest` + +Type: `string` + +Possible values: `jest`, `none` + +Adds the specified unit test runner diff --git a/docs/node/api-gatsby/generators/component.md b/docs/node/api-gatsby/generators/component.md new file mode 100644 index 0000000000..505bd2d0d8 --- /dev/null +++ b/docs/node/api-gatsby/generators/component.md @@ -0,0 +1,107 @@ +# component + +Create a component + +## Usage + +```bash +nx generate component ... +``` + +By default, Nx will search for `component` in the default collection provisioned in `workspace.json`. + +You can specify the collection explicitly as follows: + +```bash +nx g @nrwl/gatsby:component ... +``` + +Show what will be generated without writing to disk: + +```bash +nx g component ... --dry-run +``` + +### Examples + +Generate a component in the mylib library: + +```bash +nx g component my-component --project=mylib +``` + +Generate a class component in the mylib library: + +```bash +nx g component my-component --project=mylib --classComponent +``` + +## Options + +### directory + +Alias(es): d + +Type: `string` + +Create the component under this directory (can be nested). + +### export + +Alias(es): e + +Default: `false` + +Type: `boolean` + +When true, the component is exported from the project index.ts (if it exists). + +### flat + +Default: `false` + +Type: `boolean` + +Create component at the source root rather than its own directory. + +### js + +Default: `false` + +Type: `boolean` + +Generate JavaScript files rather than TypeScript files. + +### name + +Type: `string` + +The name of the component. + +### project + +Alias(es): p + +Type: `string` + +The name of the project. + +### skipTests + +Default: `false` + +Type: `boolean` + +When true, does not create "spec.ts" test files for the new component. + +### style + +Alias(es): s + +Default: `css` + +Type: `string` + +Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/styled`, `none` + +The file extension to be used for style files. diff --git a/docs/node/api-gatsby/generators/page.md b/docs/node/api-gatsby/generators/page.md new file mode 100644 index 0000000000..9310106396 --- /dev/null +++ b/docs/node/api-gatsby/generators/page.md @@ -0,0 +1,107 @@ +# page + +Create a page + +## Usage + +```bash +nx generate page ... +``` + +By default, Nx will search for `page` in the default collection provisioned in `workspace.json`. + +You can specify the collection explicitly as follows: + +```bash +nx g @nrwl/gatsby:page ... +``` + +Show what will be generated without writing to disk: + +```bash +nx g page ... --dry-run +``` + +### Examples + +Generate a page in the mylib library: + +```bash +nx g page my-page --project=mylib +``` + +Generate a class component in the mylib library: + +```bash +nx g page my-page --project=mylib --classComponent +``` + +## Options + +### directory + +Alias(es): d + +Type: `string` + +Create the component under this directory (can be nested). + +### export + +Alias(es): e + +Default: `false` + +Type: `boolean` + +When true, the component is exported from the project index.ts (if it exists). + +### flat + +Default: `false` + +Type: `boolean` + +Create component at the source root rather than its own directory. + +### js + +Default: `false` + +Type: `boolean` + +Generate JavaScript files rather than TypeScript files. + +### name + +Type: `string` + +The name of the component. + +### project + +Alias(es): p + +Type: `string` + +The name of the project. + +### skipTests + +Default: `false` + +Type: `boolean` + +When true, does not create "spec.ts" test files for the new component. + +### style + +Alias(es): s + +Default: `css` + +Type: `string` + +Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/styled`, `none` + +The file extension to be used for style files. diff --git a/docs/node/executors.json b/docs/node/executors.json index 722846ec08..ded073647f 100644 --- a/docs/node/executors.json +++ b/docs/node/executors.json @@ -2,6 +2,7 @@ "angular", "cypress", "express", + "gatsby", "jest", "linter", "nest", diff --git a/docs/node/generators.json b/docs/node/generators.json index ae621ac6e8..46a738dc38 100644 --- a/docs/node/generators.json +++ b/docs/node/generators.json @@ -2,6 +2,7 @@ "angular", "cypress", "express", + "gatsby", "jest", "nest", "next", diff --git a/docs/react/api-gatsby/executors/build.md b/docs/react/api-gatsby/executors/build.md new file mode 100644 index 0000000000..72d1ac9f40 --- /dev/null +++ b/docs/react/api-gatsby/executors/build.md @@ -0,0 +1,48 @@ +# build + +Build a Gatsby app + +Properties can be configured in workspace.json when defining the executor, or when invoking it. +Read more about how to use executors and the CLI here: https://nx.dev/react/guides/cli. + +## Properties + +### color + +Default: `true` + +Type: `boolean` + +Enable colored terminal output. + +### graphqlTracing + +Type: `boolean` + +Trace every graphql resolver, may have performance implications. + +### openTracingConfigFile + +Type: `string` + +Tracer configuration file (OpenTracing compatible). + +### prefixPaths + +Type: `boolean` + +Build site with link paths prefixed (set pathPrefix in your config). + +### profile + +Type: `boolean` + +Build site with react profiling. + +### uglify + +Default: `true` + +Type: `boolean` + +Build site without uglifying JS bundles (true by default). diff --git a/docs/react/api-gatsby/executors/server.md b/docs/react/api-gatsby/executors/server.md new file mode 100644 index 0000000000..46aae31a1c --- /dev/null +++ b/docs/react/api-gatsby/executors/server.md @@ -0,0 +1,44 @@ +# server + +Starts server for app + +Properties can be configured in workspace.json when defining the executor, or when invoking it. +Read more about how to use executors and the CLI here: https://nx.dev/react/guides/cli. + +## Properties + +### buildTarget + +Type: `string` + +Target which builds the application + +### host + +Default: `localhost` + +Type: `string` + +Host to listen on. + +### https + +Default: `false` + +Type: `boolean` + +Serve using HTTPS. + +### open + +Type: `boolean` + +Open the site in your (default) browser for you. + +### port + +Default: `4200` + +Type: `number` + +Port to listen on. diff --git a/docs/react/api-gatsby/generators/application.md b/docs/react/api-gatsby/generators/application.md new file mode 100644 index 0000000000..444d19ee1b --- /dev/null +++ b/docs/react/api-gatsby/generators/application.md @@ -0,0 +1,89 @@ +# application + +Create an application + +## Usage + +```bash +nx generate application ... +``` + +```bash +nx g app ... # same +``` + +By default, Nx will search for `application` in the default collection provisioned in `workspace.json`. + +You can specify the collection explicitly as follows: + +```bash +nx g @nrwl/gatsby:application ... +``` + +Show what will be generated without writing to disk: + +```bash +nx g application ... --dry-run +``` + +## Options + +### directory + +Alias(es): d + +Type: `string` + +A directory where the project is placed + +### e2eTestRunner + +Default: `cypress` + +Type: `string` + +Possible values: `cypress`, `none` + +Adds the specified e2e test runner + +### js + +Default: `false` + +Type: `boolean` + +Generate JavaScript files rather than TypeScript files + +### name + +Type: `string` + +### style + +Alias(es): s + +Default: `css` + +Type: `string` + +Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/styled`, `none` + +The file extension to be used for style files. + +### tags + +Alias(es): t + +Type: `string` + +Add tags to the project (used for linting) + +### unitTestRunner + +Default: `jest` + +Type: `string` + +Possible values: `jest`, `none` + +Adds the specified unit test runner diff --git a/docs/react/api-gatsby/generators/component.md b/docs/react/api-gatsby/generators/component.md new file mode 100644 index 0000000000..505bd2d0d8 --- /dev/null +++ b/docs/react/api-gatsby/generators/component.md @@ -0,0 +1,107 @@ +# component + +Create a component + +## Usage + +```bash +nx generate component ... +``` + +By default, Nx will search for `component` in the default collection provisioned in `workspace.json`. + +You can specify the collection explicitly as follows: + +```bash +nx g @nrwl/gatsby:component ... +``` + +Show what will be generated without writing to disk: + +```bash +nx g component ... --dry-run +``` + +### Examples + +Generate a component in the mylib library: + +```bash +nx g component my-component --project=mylib +``` + +Generate a class component in the mylib library: + +```bash +nx g component my-component --project=mylib --classComponent +``` + +## Options + +### directory + +Alias(es): d + +Type: `string` + +Create the component under this directory (can be nested). + +### export + +Alias(es): e + +Default: `false` + +Type: `boolean` + +When true, the component is exported from the project index.ts (if it exists). + +### flat + +Default: `false` + +Type: `boolean` + +Create component at the source root rather than its own directory. + +### js + +Default: `false` + +Type: `boolean` + +Generate JavaScript files rather than TypeScript files. + +### name + +Type: `string` + +The name of the component. + +### project + +Alias(es): p + +Type: `string` + +The name of the project. + +### skipTests + +Default: `false` + +Type: `boolean` + +When true, does not create "spec.ts" test files for the new component. + +### style + +Alias(es): s + +Default: `css` + +Type: `string` + +Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/styled`, `none` + +The file extension to be used for style files. diff --git a/docs/react/api-gatsby/generators/page.md b/docs/react/api-gatsby/generators/page.md new file mode 100644 index 0000000000..9310106396 --- /dev/null +++ b/docs/react/api-gatsby/generators/page.md @@ -0,0 +1,107 @@ +# page + +Create a page + +## Usage + +```bash +nx generate page ... +``` + +By default, Nx will search for `page` in the default collection provisioned in `workspace.json`. + +You can specify the collection explicitly as follows: + +```bash +nx g @nrwl/gatsby:page ... +``` + +Show what will be generated without writing to disk: + +```bash +nx g page ... --dry-run +``` + +### Examples + +Generate a page in the mylib library: + +```bash +nx g page my-page --project=mylib +``` + +Generate a class component in the mylib library: + +```bash +nx g page my-page --project=mylib --classComponent +``` + +## Options + +### directory + +Alias(es): d + +Type: `string` + +Create the component under this directory (can be nested). + +### export + +Alias(es): e + +Default: `false` + +Type: `boolean` + +When true, the component is exported from the project index.ts (if it exists). + +### flat + +Default: `false` + +Type: `boolean` + +Create component at the source root rather than its own directory. + +### js + +Default: `false` + +Type: `boolean` + +Generate JavaScript files rather than TypeScript files. + +### name + +Type: `string` + +The name of the component. + +### project + +Alias(es): p + +Type: `string` + +The name of the project. + +### skipTests + +Default: `false` + +Type: `boolean` + +When true, does not create "spec.ts" test files for the new component. + +### style + +Alias(es): s + +Default: `css` + +Type: `string` + +Possible values: `css`, `scss`, `styl`, `less`, `styled-components`, `@emotion/styled`, `none` + +The file extension to be used for style files. diff --git a/docs/react/executors.json b/docs/react/executors.json index 722846ec08..ded073647f 100644 --- a/docs/react/executors.json +++ b/docs/react/executors.json @@ -2,6 +2,7 @@ "angular", "cypress", "express", + "gatsby", "jest", "linter", "nest", diff --git a/docs/react/generators.json b/docs/react/generators.json index ae621ac6e8..46a738dc38 100644 --- a/docs/react/generators.json +++ b/docs/react/generators.json @@ -2,6 +2,7 @@ "angular", "cypress", "express", + "gatsby", "jest", "nest", "next", diff --git a/docs/shared/gatsby-plugin.md b/docs/shared/gatsby-plugin.md new file mode 100644 index 0000000000..e3d47d2402 --- /dev/null +++ b/docs/shared/gatsby-plugin.md @@ -0,0 +1,73 @@ +# Next.js Plugin + +The Nx Plugin for Next.js contains executors and generators for managing Next.js applications and libraries within an Nx workspace. It provides: + +- Scaffolding for creating, building, serving, linting, and testing Next.js applications. +- Integration with building, serving, and exporting a Next.js application. +- Integration with React libraries within the workspace. + +## Installing the Next.js Plugin + +Installing the Next plugin to a workspace can be done with the following: + +```shell script +yarn add -D @nrwl/next +``` + +```shell script +npm install -D @nrwl/next +``` + +## Applications + +Generating new applications can be done with the following: + +```shell script +nx generate @nrwl/next:application +``` + +This creates the following app structure: + +```treeview +myorg/ +├── apps/ +│   ├── myapp/ +│   │   ├── pages/ +│   │   │   ├── index.css +│   │   │   └── index.tsx +│   │   ├── jest.conf.js +│   │   ├── tsconfig.json +│   │   ├── tsconfig.spec.json +│   │   └── .eslintrc.json +│   └── myapp-e2e/ +│   │   ├── src/ +│   │   │   ├── integrations/ +│   │   │   │   └── app.spec.ts +│   │   │   ├── fixtures/ +│   │   │   ├── plugins/ +│   │   │   └── support/ +│   │   ├── cypress.json +│   │   ├── tsconfig.e2e.json +│   │   └── .eslintrc.json +├── libs/ +├── workspace.json +├── nx.json +├── package.json +├── tools/ +├── tsconfig.json +└── .eslintrc.json +``` + +## See Also + +- [Using Next.js](https://nextjs.org/docs/getting-started) + +## Executors / Builders + +- [build](/{{framework}}/plugins/next/executors/build) - Builds a Next.js application +- [dev-server](/{{framework}}/plugins/next/executors/dev-server) - Builds and serves a Next.js application +- [export](/{{framework}}/plugins/next/executors/package) - Export a Next.js app. The exported application is located at `dist/$outputPath/exported` + +## Generators + +- [application](/{{framework}}/plugins/next/generators/application) - Create an Next.js application diff --git a/docs/shared/next-plugin.md b/docs/shared/next-plugin.md index e3d47d2402..5ab8efa4a6 100644 --- a/docs/shared/next-plugin.md +++ b/docs/shared/next-plugin.md @@ -1,21 +1,21 @@ -# Next.js Plugin +# Gatsby Plugin -The Nx Plugin for Next.js contains executors and generators for managing Next.js applications and libraries within an Nx workspace. It provides: +The Nx Plugin for Gatsby contains executors and generators for managing Gatsby applications and libraries within an Nx workspace. It provides: -- Scaffolding for creating, building, serving, linting, and testing Next.js applications. -- Integration with building, serving, and exporting a Next.js application. +- Scaffolding for creating, building, serving, linting, and testing Gatsby applications. +- Integration with building, serving, and exporting a Gatsby application. - Integration with React libraries within the workspace. -## Installing the Next.js Plugin +## Installing the Gatsby Plugin -Installing the Next plugin to a workspace can be done with the following: +Installing the Gatsby plugin to a workspace can be done with the following: ```shell script -yarn add -D @nrwl/next +yarn add -D @nrwl/gatsby ``` ```shell script -npm install -D @nrwl/next +npm install -D @nrwl/gatsby ``` ## Applications @@ -23,7 +23,7 @@ npm install -D @nrwl/next Generating new applications can be done with the following: ```shell script -nx generate @nrwl/next:application +nx generate @nrwl/gatsby:application ``` This creates the following app structure: @@ -32,11 +32,13 @@ This creates the following app structure: myorg/ ├── apps/ │   ├── myapp/ -│   │   ├── pages/ -│   │   │   ├── index.css -│   │   │   └── index.tsx +│   │   ├── src/ +│   │   │   ├── pages/ +│   │   │   │   ├── index.module.css +│   │   │   │   └── index.tsx │   │   ├── jest.conf.js │   │   ├── tsconfig.json +│   │   ├── tsconfig.app.json │   │   ├── tsconfig.spec.json │   │   └── .eslintrc.json │   └── myapp-e2e/ @@ -60,14 +62,15 @@ myorg/ ## See Also -- [Using Next.js](https://nextjs.org/docs/getting-started) +- [Using Gatsby](https://www.gatsbyjs.com/docs/quick-start/) ## Executors / Builders -- [build](/{{framework}}/plugins/next/executors/build) - Builds a Next.js application -- [dev-server](/{{framework}}/plugins/next/executors/dev-server) - Builds and serves a Next.js application -- [export](/{{framework}}/plugins/next/executors/package) - Export a Next.js app. The exported application is located at `dist/$outputPath/exported` +- [build](/{{framework}}/plugins/gatsby/executors/build) - Builds a Gatsby application +- [server](/{{framework}}/plugins/gatsby/executors/server) - Builds and serves a Gatsby application ## Generators -- [application](/{{framework}}/plugins/next/generators/application) - Create an Next.js application +- [application](/{{framework}}/plugins/gatsby/generators/application) - Create a Gatsby application +- [component](/{{framework}}/plugins/gatsby/generators/component) - Create a Gatsby component +- [page](/{{framework}}/plugins/gatsby/generators/page) - Create a Gatsby page diff --git a/e2e/gatsby/jest.config.js b/e2e/gatsby/jest.config.js new file mode 100644 index 0000000000..20df9ab064 --- /dev/null +++ b/e2e/gatsby/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + preset: '../../jest.preset.js', + transform: { + '^.+\\.[tj]sx?$': 'ts-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], + maxWorkers: 1, + globals: { 'ts-jest': { tsConfig: '/tsconfig.spec.json' } }, + displayName: 'e2e-next', +}; diff --git a/e2e/gatsby/src/gatsby.test.ts b/e2e/gatsby/src/gatsby.test.ts new file mode 100644 index 0000000000..6a1aa9d5a6 --- /dev/null +++ b/e2e/gatsby/src/gatsby.test.ts @@ -0,0 +1,59 @@ +import { + checkFilesExist, + newProject, + runCLI, + runCLIAsync, + uniq, + updateFile, +} from '@nrwl/e2e/utils'; + +describe('Gatsby Applications', () => { + let proj: string; + + beforeEach(() => (proj = newProject())); + + it('should generate a valid gatsby application', async () => { + const appName = uniq('app'); + runCLI(`generate @nrwl/gatsby:app ${appName}`); + runCLI(`generate @nrwl/gatsby:component header --project ${appName}`); + + checkFilesExist( + `apps/${appName}/package.json`, + `apps/${appName}/src/components/header.tsx`, + `apps/${appName}/src/components/header.spec.tsx`, + `apps/${appName}/src/pages/index.tsx`, + `apps/${appName}/src/pages/index.spec.tsx` + ); + + updateFile(`apps/${appName}/src/pages/index.tsx`, (content) => { + let updated = `import Header from '../components/header';\n${content}`; + updated = updated.replace('
', '
'); + return updated; + }); + + let result = runCLI(`build ${appName}`); + expect(result).toContain('Done building in'); + + result = runCLI(`lint ${appName}`); + expect(result).not.toMatch('Lint errors found in the listed files'); + + const testResults = await runCLIAsync(`test ${appName}`); + expect(testResults.combinedOutput).toContain( + 'Test Suites: 2 passed, 2 total' + ); + }, 120000); + + test('supports --js option', async () => { + const app = uniq('app'); + runCLI(`generate @nrwl/gatsby:app ${app} --js`); + + checkFilesExist( + `apps/${app}/package.json`, + `apps/${app}/src/pages/index.js`, + `apps/${app}/src/pages/index.spec.js` + ); + + const result = runCLI(`build ${app}`); + expect(result).toContain('Done building in'); + }, 120000); +}); diff --git a/e2e/gatsby/tsconfig.json b/e2e/gatsby/tsconfig.json new file mode 100644 index 0000000000..6d5abf8483 --- /dev/null +++ b/e2e/gatsby/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "types": ["node", "jest"] + }, + "include": [], + "files": [], + "references": [ + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/e2e/gatsby/tsconfig.spec.json b/e2e/gatsby/tsconfig.spec.json new file mode 100644 index 0000000000..af4ac638d6 --- /dev/null +++ b/e2e/gatsby/tsconfig.spec.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "**/*.test.ts", + "**/*.spec.ts", + "**/*.spec.tsx", + "**/*.spec.js", + "**/*.spec.jsx", + "**/*.d.ts" + ] +} diff --git a/e2e/utils/index.ts b/e2e/utils/index.ts index 983b4b3920..9d8640ec1e 100644 --- a/e2e/utils/index.ts +++ b/e2e/utils/index.ts @@ -139,6 +139,7 @@ export function newProject({ name = uniq('proj') } = {}): string { `@nrwl/express`, `@nrwl/nest`, `@nrwl/next`, + `@nrwl/gatsby`, `@nrwl/node`, `@nrwl/react`, `@nrwl/storybook`, diff --git a/images/nx-gatsby.png b/images/nx-gatsby.png new file mode 100644 index 0000000000..ef9746bcbd Binary files /dev/null and b/images/nx-gatsby.png differ diff --git a/jest.config.js b/jest.config.js index b4bf8dcf04..8dac1b30b5 100644 --- a/jest.config.js +++ b/jest.config.js @@ -18,5 +18,6 @@ module.exports = { '/packages/create-nx-plugin', '/packages/cli', '/packages/angular', + '/packages/gatsby', ], }; diff --git a/nx.json b/nx.json index d2fd4ea908..770ca88310 100644 --- a/nx.json +++ b/nx.json @@ -124,6 +124,10 @@ "tags": [], "implicitDependencies": ["cypress"] }, + "e2e-gatsby": { + "tags": [], + "implicitDependencies": ["gatsby"] + }, "e2e-jest": { "tags": [], "implicitDependencies": ["jest"] @@ -166,6 +170,9 @@ "dep-graph-client-e2e": { "tags": [], "implicitDependencies": ["dep-graph-client"] + }, + "gatsby": { + "tags": [] } }, "affected": { diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts index 48055f94fc..147ecea914 100644 --- a/packages/create-nx-workspace/bin/create-nx-workspace.ts +++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts @@ -30,6 +30,10 @@ const presetOptions: { value: Preset; name: string }[] = [ value: Preset.NextJs, name: 'next.js [a workspace with a single Next.js application]', }, + { + value: Preset.Gatsby, + name: 'gatsby [a workspace with a single Gatsby application]', + }, { value: Preset.Nest, name: 'nest [a workspace with a single Nest application]', @@ -480,6 +484,7 @@ function pointToTutorialAndCourse(preset: Preset) { case Preset.React: case Preset.ReactWithExpress: case Preset.NextJs: + case Preset.Gatsby: output.addVerticalSeparator(); output.note({ title: title, diff --git a/packages/gatsby/.eslintrc.json b/packages/gatsby/.eslintrc.json new file mode 100644 index 0000000000..9afd5d63f0 --- /dev/null +++ b/packages/gatsby/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "extends": "../../.eslintrc", + "rules": {}, + "ignorePatterns": ["!**/*"] +} diff --git a/packages/gatsby/README.md b/packages/gatsby/README.md new file mode 100644 index 0000000000..6323a61c13 --- /dev/null +++ b/packages/gatsby/README.md @@ -0,0 +1,40 @@ +

+ +{{links}} + +
+ +# Gatsby Plugin for Nx + +{{what-is-nx}} + +{{getting-started}} + +``` +? Workspace name (e.g., org name) happyorg +? What to create in the new workspace gatsby [a workspace with a single Gatsby application] +? Application name myapp +? Default stylesheet format CSS +``` + +You can also select `empty` and add `@nrwl/gatsby` plugin using yarn or npm, and then generate a new express app using `nx g @nrwl/gatsby:app myapp`. + +If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm. + +### Serving Application + +- Run `nx serve myapp` to serve the newly generated application! +- Run `nx test myapp` to test it. +- Run `nx e2e myapp` to run e2e tests for your application. + +You are good to go! + +## Quick Start Videos + + +

+
+ +- [Nx Dev Tools for Monorepos, In-Depth Explainer (React)](https://www.youtube.com/watch?v=jCf92IyR-GE) + +{{resources}} diff --git a/packages/gatsby/babel.ts b/packages/gatsby/babel.ts new file mode 100644 index 0000000000..65f2393365 --- /dev/null +++ b/packages/gatsby/babel.ts @@ -0,0 +1,9 @@ +/* + * Babel preset to provide Gatsby support for Nx. + */ +module.exports = function (api, options) { + api.assertVersion(7); + return { + presets: [[require.resolve('babel-preset-gatsby'), { useBuiltIns: true }]], + }; +}; diff --git a/packages/gatsby/builders.json b/packages/gatsby/builders.json new file mode 100644 index 0000000000..88fbc9181c --- /dev/null +++ b/packages/gatsby/builders.json @@ -0,0 +1,15 @@ +{ + "$schema": "@angular-devkit/architect/src/builders-schema.json", + "builders": { + "build": { + "implementation": "./src/builders/build/builder", + "schema": "./src/builders/build/schema.json", + "description": "Build a Gatsby app" + }, + "server": { + "implementation": "./src/builders/server/builder", + "schema": "./src/builders/server/schema.json", + "description": "Starts server for app" + } + } +} diff --git a/packages/gatsby/collection.json b/packages/gatsby/collection.json new file mode 100644 index 0000000000..6208ed71ab --- /dev/null +++ b/packages/gatsby/collection.json @@ -0,0 +1,29 @@ +{ + "name": "nx/gatsby", + "version": "0.1", + "extends": ["@nrwl/react"], + "schematics": { + "init": { + "factory": "./src/schematics/init/init", + "schema": "./src/schematics/init/schema.json", + "description": "Initialize the @nrwl/gatsby plugin", + "hidden": true + }, + "application": { + "factory": "./src/schematics/application/application", + "schema": "./src/schematics/application/schema.json", + "aliases": ["app"], + "description": "Create an application" + }, + "component": { + "factory": "./src/schematics/component/component", + "schema": "./src/schematics/component/schema.json", + "description": "Create a component" + }, + "page": { + "factory": "./src/schematics/page/page", + "schema": "./src/schematics/page/schema.json", + "description": "Create a page" + } + } +} diff --git a/packages/gatsby/index.ts b/packages/gatsby/index.ts new file mode 100644 index 0000000000..85b66a09ea --- /dev/null +++ b/packages/gatsby/index.ts @@ -0,0 +1,3 @@ +export { applicationGenerator } from './src/schematics/application/application'; +export { componentGenerator } from './src/schematics/component/component'; +export { pageGenerator } from './src/schematics/page/page'; diff --git a/packages/gatsby/jest.config.js b/packages/gatsby/jest.config.js new file mode 100644 index 0000000000..338780b932 --- /dev/null +++ b/packages/gatsby/jest.config.js @@ -0,0 +1,9 @@ +module.exports = { + preset: '../../jest.preset.js', + transform: { + '^.+\\.[tj]sx?$': 'ts-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], + globals: { 'ts-jest': { tsConfig: '/tsconfig.spec.json' } }, + displayName: 'gatsby', +}; diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json new file mode 100644 index 0000000000..7d9cf263de --- /dev/null +++ b/packages/gatsby/package.json @@ -0,0 +1,41 @@ +{ + "name": "@nrwl/gatsby", + "version": "0.0.1", + "description": "Gatsby Plugin for Nx", + "repository": { + "type": "git", + "url": "git+https://github.com/nrwl/nx.git" + }, + "keywords": [ + "Monorepo", + "Node", + "Express", + "Jest", + "Cypress", + "CLI" + ], + "main": "index.js", + "types": "index.d.ts", + "author": "Victor Savkin", + "license": "MIT", + "bugs": { + "url": "https://github.com/nrwl/nx/issues" + }, + "homepage": "https://nx.dev", + "schematics": "./collection.json", + "builders": "./builders.json", + "ng-update": { + "requirements": {}, + "migrations": "./migrations.json" + }, + "dependencies": { + "@angular-devkit/core": "~11.0.1", + "@angular-devkit/schematics": "~11.0.1", + "@nrwl/cypress": "*", + "@nrwl/devkit": "*", + "@nrwl/jest": "*", + "@nrwl/node": "*", + "@nrwl/react": "*", + "gatsby-cli": "^2.17.1" + } +} diff --git a/packages/gatsby/plugins/nx-gatsby-ext-plugin/gatsby-config.ts b/packages/gatsby/plugins/nx-gatsby-ext-plugin/gatsby-config.ts new file mode 100644 index 0000000000..7b21fd565d --- /dev/null +++ b/packages/gatsby/plugins/nx-gatsby-ext-plugin/gatsby-config.ts @@ -0,0 +1,3 @@ +module.exports = { + plugins: [`gatsby-plugin-typescript`], +}; diff --git a/packages/gatsby/plugins/nx-gatsby-ext-plugin/gatsby-node.ts b/packages/gatsby/plugins/nx-gatsby-ext-plugin/gatsby-node.ts new file mode 100644 index 0000000000..963be0f342 --- /dev/null +++ b/packages/gatsby/plugins/nx-gatsby-ext-plugin/gatsby-node.ts @@ -0,0 +1,26 @@ +import * as path from 'path'; +import { appRootPath as workspaceRoot } from '@nrwl/workspace/src/utils/app-root'; +import { readJsonFile } from '@nrwl/workspace'; + +function onCreateBabelConfig({ actions }, options) { + const tsConfig = readJsonFile(path.join(workspaceRoot, 'tsconfig.base.json')); + const tsConfigPaths: { [key: string]: Array } = + tsConfig.compilerOptions.paths; + + const paths = Object.entries(tsConfigPaths).reduce((result, [key, paths]) => { + return { + ...result, + [key]: paths.map((p) => path.join(workspaceRoot, p)), + }; + }, {}); + + actions.setBabelPlugin({ + name: require.resolve(`babel-plugin-module-resolver`), + options: { + root: ['./src'], + alias: paths, + }, + }); +} + +export { onCreateBabelConfig }; diff --git a/packages/gatsby/plugins/nx-gatsby-ext-plugin/package.json b/packages/gatsby/plugins/nx-gatsby-ext-plugin/package.json new file mode 100644 index 0000000000..2b0b8b2312 --- /dev/null +++ b/packages/gatsby/plugins/nx-gatsby-ext-plugin/package.json @@ -0,0 +1,10 @@ +{ + "name": "nx-gatsby-ext-plugin", + "version": "1.0.0", + "main": "gatsby-config.js", + "author": "max koretskyi", + "license": "MIT", + "peerDependencies": { + "gatsby": "^2.6.0" + } +} diff --git a/packages/gatsby/src/builders/build/builder.ts b/packages/gatsby/src/builders/build/builder.ts new file mode 100644 index 0000000000..2d879b0ef9 --- /dev/null +++ b/packages/gatsby/src/builders/build/builder.ts @@ -0,0 +1,93 @@ +import { + BuilderContext, + BuilderOutput, + createBuilder, +} from '@angular-devkit/architect'; +import { fork } from 'child_process'; +import { join } from 'path'; +import { from, Observable } from 'rxjs'; +import { concatMap } from 'rxjs/operators'; +import { GatsbyPluginBuilderSchema } from './schema'; +import { getProjectRoot } from '../../utils/get-project-root'; + +export function runBuilder( + options: GatsbyPluginBuilderSchema, + context: BuilderContext +): Observable { + return from(getProjectRoot(context)).pipe( + concatMap((projectRoot) => { + return new Observable((subscriber) => { + runGatsbyBuild(context.workspaceRoot, projectRoot, options) + .then(() => { + subscriber.next({ + success: true, + }); + subscriber.complete(); + }) + .catch((err) => { + context.logger.error('Error during build', err); + subscriber.next({ + success: false, + }); + subscriber.complete(); + }); + }); + }) + ); +} + +export function runGatsbyBuild( + workspaceRoot: string, + projectRoot: string, + options: GatsbyPluginBuilderSchema +) { + return new Promise((resolve, reject) => { + const cp = fork( + require.resolve('gatsby-cli'), + ['build', ...createGatsbyBuildOptions(options)], + { + cwd: join(workspaceRoot, projectRoot), + } + ); + + cp.on('error', (err) => { + reject(err); + }); + + cp.on('exit', (code) => { + if (code === 0) { + resolve(); + } else { + reject(code); + } + }); + }); +} + +function createGatsbyBuildOptions(options: GatsbyPluginBuilderSchema) { + return Object.keys(options).reduce((acc, k) => { + const val = options[k]; + if (typeof val === 'undefined') return acc; + switch (k) { + case 'prefixPaths': + return val ? acc.concat(`--prefix-paths`) : acc; + case 'uglify': + return val ? acc : acc.concat('--no-uglify'); + case 'color': + return val ? acc : acc.concat('--no-color'); + case 'profile': + return val ? acc.concat('--profile') : acc; + case 'openTracingConfigFile': + return val ? acc.concat([`--open-tracing-config-file`, val]) : acc; + case 'graphqlTracing': + return val ? acc.concat('--graphql-tracing') : acc; + case 'serve': + case 'host': + case 'port': + default: + return acc; + } + }, []); +} + +export default createBuilder(runBuilder); diff --git a/packages/gatsby/src/builders/build/schema.d.ts b/packages/gatsby/src/builders/build/schema.d.ts new file mode 100644 index 0000000000..894d9d535c --- /dev/null +++ b/packages/gatsby/src/builders/build/schema.d.ts @@ -0,0 +1,10 @@ +import { JsonObject } from '@angular-devkit/core'; + +export interface GatsbyPluginBuilderSchema extends JsonObject { + prefixPaths?: boolean; + uglify: boolean; + profile?: boolean; + openTracingConfigFile?: string; + graphqlTracing?: boolean; + color: boolean; +} diff --git a/packages/gatsby/src/builders/build/schema.json b/packages/gatsby/src/builders/build/schema.json new file mode 100644 index 0000000000..cc1e750a3d --- /dev/null +++ b/packages/gatsby/src/builders/build/schema.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/schema", + "title": "GatsbyPlugin builder", + "description": "", + "type": "object", + "properties": { + "prefixPaths": { + "type": "boolean", + "description": "Build site with link paths prefixed (set pathPrefix in your config)." + }, + "uglify": { + "type": "boolean", + "description": "Build site without uglifying JS bundles (true by default).", + "default": true + }, + "profile": { + "type": "boolean", + "description": "Build site with react profiling." + }, + "openTracingConfigFile": { + "type": "string", + "description": "Tracer configuration file (OpenTracing compatible)." + }, + "graphqlTracing": { + "type": "boolean", + "description": "Trace every graphql resolver, may have performance implications." + }, + "color": { + "type": "boolean", + "description": "Enable colored terminal output.", + "default": true + } + }, + "required": [] +} diff --git a/packages/gatsby/src/builders/server/builder.ts b/packages/gatsby/src/builders/server/builder.ts new file mode 100644 index 0000000000..8ea346440a --- /dev/null +++ b/packages/gatsby/src/builders/server/builder.ts @@ -0,0 +1,161 @@ +import { + BuilderContext, + BuilderOutput, + createBuilder, + targetFromTargetString, +} from '@angular-devkit/architect'; +import { fork } from 'child_process'; +import { join } from 'path'; +import { from, Observable, of } from 'rxjs'; +import { catchError, concatMap, withLatestFrom } from 'rxjs/operators'; +import { GatsbyPluginBuilderSchema } from './schema'; +import { runGatsbyBuild } from '../build/builder'; +import { GatsbyPluginBuilderSchema as BuildBuilderSchema } from '../build/schema'; +import { getProjectRoot } from '../../utils/get-project-root'; + +export function runBuilder( + options: GatsbyPluginBuilderSchema, + context: BuilderContext +): Observable { + const buildTarget = targetFromTargetString(options.buildTarget); + const baseUrl = `${options.https ? 'https' : 'http'}://${options.host}:${ + options.port + }`; + return from(getProjectRoot(context)).pipe( + concatMap((projectRoot) => { + return from(context.getTargetOptions(buildTarget)).pipe( + concatMap((buildOptions: BuildBuilderSchema) => { + return new Observable((subscriber) => { + if (context.target.configuration === 'production') { + runGatsbyBuild(context.workspaceRoot, projectRoot, buildOptions) + .then(() => + runGatsbyServe(context.workspaceRoot, projectRoot, options) + ) + .then(() => { + subscriber.next({ + success: true, + }); + }) + .catch((err) => { + context.logger.error('Error during serve', err); + }); + } else { + runGatsbyDevelop( + context.workspaceRoot, + projectRoot, + createGatsbyOptions(options) + ) + .then((success) => { + subscriber.next({ + baseUrl, + success, + }); + }) + .catch((err) => { + context.logger.error('Error during serve', err?.message); + subscriber.next({ + success: false, + }); + subscriber.complete(); + }); + } + }); + }), + catchError((err) => { + context.logger.error(err); + return of({ success: false }); + }) + ); + }) + ); +} + +function createGatsbyOptions(options) { + return Object.keys(options).reduce((acc, k) => { + if (k === 'port' || k === 'host' || k === 'https' || k === 'open') + acc.push(`--${k}=${options[k]}`); + return acc; + }, []); +} + +async function runGatsbyDevelop(workspaceRoot, projectRoot, options) { + return new Promise((resolve, reject) => { + const cp = fork(require.resolve('gatsby-cli'), ['develop', ...options], { + cwd: join(workspaceRoot, projectRoot), + env: { + ...process.env, + }, + stdio: ['inherit', 'inherit', 'inherit', 'ipc'], + }); + + // Ensure the child process is killed when the parent exits + process.on('exit', () => cp.kill()); + + cp.on('message', ({ action }) => { + if ( + action?.type === 'ACTIVITY_END' && + action?.payload?.status === 'SUCCESS' && + action?.payload?.id === 'webpack-develop' + ) { + resolve(true); + } + }); + + cp.on('error', (err) => { + reject(err); + }); + + cp.on('exit', (code) => { + if (code !== 0) { + reject(code); + } + }); + }); +} + +function runGatsbyServe( + workspaceRoot: string, + projectRoot: string, + options: GatsbyPluginBuilderSchema +) { + return new Promise((resolve, reject) => { + const cp = fork( + require.resolve('gatsby-cli'), + ['serve', ...createGatsbyServeOptions(options)], + { cwd: join(workspaceRoot, projectRoot) } + ); + + cp.on('error', (err) => { + reject(err); + }); + + cp.on('exit', (code) => { + if (code === 0) { + resolve(code); + } else { + reject(code); + } + }); + }); +} + +function createGatsbyServeOptions(options: GatsbyPluginBuilderSchema) { + return Object.keys(options).reduce((acc, k) => { + const val = options[k]; + if (typeof val === 'undefined') return acc; + switch (k) { + case 'host': + return val ? acc.concat([`--host`, val]) : acc; + case 'open': + return val ? acc.concat(`--open`) : acc; + case 'prefixPaths': + return val ? acc.concat(`--prefix-paths`) : acc; + case 'port': + return val ? acc.concat([`--port`, val]) : acc; + default: + return acc; + } + }, []); +} + +export default createBuilder(runBuilder); diff --git a/packages/gatsby/src/builders/server/schema.d.ts b/packages/gatsby/src/builders/server/schema.d.ts new file mode 100644 index 0000000000..0c6c9f2c6e --- /dev/null +++ b/packages/gatsby/src/builders/server/schema.d.ts @@ -0,0 +1,9 @@ +import { JsonObject } from '@angular-devkit/core'; + +export interface GatsbyPluginBuilderSchema extends JsonObject { + buildTarget: string; + host: string; + port: string; + open: boolean; + https: boolean; +} diff --git a/packages/gatsby/src/builders/server/schema.json b/packages/gatsby/src/builders/server/schema.json new file mode 100644 index 0000000000..ddcc53e8ce --- /dev/null +++ b/packages/gatsby/src/builders/server/schema.json @@ -0,0 +1,31 @@ +{ + "title": "Gatsby development server", + "description": "Gatsby development server", + "type": "object", + "properties": { + "buildTarget": { + "type": "string", + "description": "Target which builds the application" + }, + "port": { + "type": "number", + "description": "Port to listen on.", + "default": 4200 + }, + "host": { + "type": "string", + "description": "Host to listen on.", + "default": "localhost" + }, + "https": { + "type": "boolean", + "description": "Serve using HTTPS.", + "default": false + }, + "open": { + "type": "boolean", + "description": "Open the site in your (default) browser for you." + } + }, + "required": [] +} diff --git a/packages/gatsby/src/index.ts b/packages/gatsby/src/index.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/gatsby/src/schematics/application/application.spec.ts b/packages/gatsby/src/schematics/application/application.spec.ts new file mode 100644 index 0000000000..054c21a3a5 --- /dev/null +++ b/packages/gatsby/src/schematics/application/application.spec.ts @@ -0,0 +1,320 @@ +import { Tree } from '@angular-devkit/schematics'; +import { NxJson, readJsonInTree } from '@nrwl/workspace'; +import { createEmptyWorkspace } from '@nrwl/workspace/testing'; +import { runSchematic } from '../../utils/testing'; + +describe('app', () => { + let appTree: Tree; + + beforeEach(() => { + appTree = Tree.empty(); + appTree = createEmptyWorkspace(appTree); + }); + + it('should update workspace.json', async () => { + const tree = await runSchematic('app', { name: 'myApp' }, appTree); + const workspaceJson = readJsonInTree(tree, '/workspace.json'); + + expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app'); + expect(workspaceJson.projects['my-app-e2e'].root).toEqual( + 'apps/my-app-e2e' + ); + expect(workspaceJson.defaultProject).toEqual('my-app'); + }); + + it('should update nx.json', async () => { + const tree = await runSchematic( + 'app', + { name: 'myApp', tags: 'one,two' }, + appTree + ); + const nxJson = readJsonInTree(tree, '/nx.json'); + expect(nxJson.projects).toEqual({ + 'my-app': { + tags: ['one', 'two'], + }, + 'my-app-e2e': { + tags: [], + implicitDependencies: ['my-app'], + }, + }); + }); + + it('should generate files', async () => { + const tree = await runSchematic('app', { name: 'myApp' }, appTree); + expect(tree.exists('apps/my-app/tsconfig.json')).toBeTruthy(); + expect(tree.exists('apps/my-app/tsconfig.app.json')).toBeTruthy(); + expect(tree.exists('apps/my-app/src/pages/index.tsx')).toBeTruthy(); + expect(tree.exists('apps/my-app/src/pages/index.spec.tsx')).toBeTruthy(); + expect(tree.exists('apps/my-app/src/pages/index.module.css')).toBeTruthy(); + }); + + describe('--style scss', () => { + it('should generate scss styles', async () => { + const result = await runSchematic( + 'app', + { name: 'myApp', style: 'scss' }, + appTree + ); + expect( + result.exists('apps/my-app/src/pages/index.module.scss') + ).toBeTruthy(); + + const indexContent = result + .read('apps/my-app/src/pages/index.tsx') + .toString(); + expect(indexContent).toContain( + `import styles from './index.module.scss'` + ); + }); + }); + + describe('--style less', () => { + it('should generate less styles', async () => { + const result = await runSchematic( + 'app', + { name: 'myApp', style: 'less' }, + appTree + ); + expect( + result.exists('apps/my-app/src/pages/index.module.less') + ).toBeTruthy(); + + const indexContent = result + .read('apps/my-app/src/pages/index.tsx') + .toString(); + expect(indexContent).toContain( + `import styles from './index.module.less'` + ); + }); + }); + + describe('--style styl', () => { + it('should generate stylus styles', async () => { + const result = await runSchematic( + 'app', + { name: 'myApp', style: 'styl' }, + appTree + ); + expect( + result.exists('apps/my-app/src/pages/index.module.styl') + ).toBeTruthy(); + + const indexContent = result + .read('apps/my-app/src/pages/index.tsx') + .toString(); + expect(indexContent).toContain( + `import styles from './index.module.styl'` + ); + }); + }); + + describe('--style styled-components', () => { + it('should generate scss styles', async () => { + const result = await runSchematic( + 'app', + { name: 'myApp', style: 'styled-components' }, + appTree + ); + expect( + result.exists('apps/my-app/src/pages/index.module.styled-components') + ).toBeFalsy(); + + const indexContent = result + .read('apps/my-app/src/pages/index.tsx') + .toString(); + expect(indexContent).not.toContain(`import styles from './index.module`); + expect(indexContent).toContain(`import styled from 'styled-components'`); + }); + }); + + describe('--style @emotion/styled', () => { + it('should generate emotion styles', async () => { + const result = await runSchematic( + 'app', + { name: 'myApp', style: '@emotion/styled' }, + appTree + ); + expect( + result.exists('apps/my-app/src/pages/index.module.styled-components') + ).toBeFalsy(); + + const indexContent = result + .read('apps/my-app/src/pages/index.tsx') + .toString(); + expect(indexContent).not.toContain(`import styles from './index.module`); + expect(indexContent).toContain(`import styled from '@emotion/styled'`); + }); + }); + + // TODO: We should also add styled-jsx support for Gatsby to keep React plugins consistent. + // This needs to be here before Nx 12 is released. + xdescribe('--style styled-jsx', () => { + it('should use