Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16f0988046 | |||
| d6afd627f4 | |||
| feb2b31d20 | |||
| 39f3282535 | |||
| ad536c4cf9 | |||
| da912b27c9 | |||
| 5d983ef157 | |||
| 0d90bc8d15 | |||
| f6b05e40c1 | |||
| d1e55b0a05 | |||
| adaee13d46 | |||
| b439c31b23 | |||
| a6642bf2a8 | |||
| bd8cbfaddd | |||
| 6f03d0c50a | |||
| 1bbeed0ac0 | |||
| c420793d5e | |||
| 16c212fc2c | |||
| 4e2d33c9e1 | |||
| 0defcad1a2 | |||
| 4233effd06 | |||
| 1488728aa3 | |||
| a627a0c26f | |||
| 75c06380c6 | |||
| 127e8d44c1 | |||
| 6e08e3f7a6 | |||
| b93d46dbc9 | |||
| 197105af9a | |||
| 84dd4180ba | |||
| f7fcc6facb | |||
| 8beb4e4424 | |||
| 7eec0d73ae | |||
| a0fb8df4d2 | |||
| 4942eb4965 | |||
| f4724bc621 | |||
| 08de51eea7 | |||
| c63bf49c97 | |||
| e7e78c56cd |
@@ -194,7 +194,7 @@ jobs:
|
||||
pnpm nx-cloud record -- nx format:check --base=$NX_BASE --head=$NX_HEAD &
|
||||
pids+=($!)
|
||||
|
||||
pnpm nx run-many -t check-imports check-commit check-lock-files depcheck --parallel=1 --no-dte &
|
||||
pnpm nx run-many -t check-imports check-commit check-lock-files depcheck check-codeowners --parallel=1 --no-dte &
|
||||
pids+=($!)
|
||||
|
||||
pnpm nx affected --target=lint --base=$NX_BASE --head=$NX_HEAD --parallel=3 &
|
||||
|
||||
@@ -2,6 +2,7 @@ name: publish
|
||||
env:
|
||||
DEBUG: napi:*
|
||||
NX_RUN_GROUP: ${{ github.run_id }}-${{ github.run_attempt }}
|
||||
NPM_CONFIG_PROVENANCE: true
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
@@ -203,6 +204,8 @@ jobs:
|
||||
if: ${{ github.repository_owner == 'nrwl' }}
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
needs:
|
||||
# - build-freebsd
|
||||
- build
|
||||
|
||||
+8
-6
@@ -11,7 +11,7 @@ pnpm-lock.yaml @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
/docs @bcabanes @isaacplmann @juristr
|
||||
/docs/nx-cloud @StalkAltan @rarmatei @isaacplmann @juristr @bcabanes
|
||||
/graph/** @philipjfulcher @FrozenPandaz @bcabanes
|
||||
/images/shared @bcabanes @isaacplmann @juristr
|
||||
/images @bcabanes @isaacplmann @juristr
|
||||
/nx-dev/** @bcabanes @isaacplmann @juristr
|
||||
/typedoc-theme @bcabanes @isaacplmann
|
||||
|
||||
@@ -76,7 +76,6 @@ pnpm-lock.yaml @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
/docs/shared/packages/web/** @jaysoo @mandarini @ndcunningham
|
||||
/docs/shared/packages/webpack/** @jaysoo @mandarini @ndcunningham
|
||||
/docs/shared/packages/esbuild/** @nartc @jaysoo @ndcunningham
|
||||
/docs/shared/packages/rollup/** @jaysoo @mandarini @ndcunningham
|
||||
/docs/shared/packages/vite/** @jaysoo @mandarini @ndcunningham
|
||||
/packages/js/** @nartc @jaysoo @ndcunningham
|
||||
/e2e/js/** @nartc @jaysoo @ndcunningham
|
||||
@@ -121,14 +120,17 @@ pnpm-lock.yaml @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
/docs/generated/devkit/** @FrozenPandaz @AgentEnder
|
||||
/docs/generated/packages/devkit/** @FrozenPandaz @AgentEnder
|
||||
/packages/devkit/** @FrozenPandaz @AgentEnder
|
||||
/packages/devkit/index.ts @FrozenPandaz @vsavkin
|
||||
/packages/devkit/index.js @FrozenPandaz @vsavkin
|
||||
/packages/devkit/index.d.ts @FrozenPandaz @vsavkin
|
||||
/packages/devkit/public-api.ts @FrozenPandaz @vsavkin
|
||||
/packages/devkit/nx.ts @FrozenPandaz @vsavkin
|
||||
/packages/devkit/src/utils/module-federation @jaysoo @Coly010
|
||||
|
||||
# Nx-Plugin
|
||||
/docs/generated/packages/plugin/** @AgentEnder @FrozenPandaz
|
||||
/docs/shared/packages/plugin/** @AgentEnder @FrozenPandaz @isaacplmann @juristr
|
||||
/packages/plugin/** @AgentEnder @FrozenPandaz
|
||||
/e2e/nx-plugin/** @AgentEnder @FrozenPandaz
|
||||
/e2e/plugin/** @AgentEnder @FrozenPandaz
|
||||
|
||||
## Core
|
||||
/docs/generated/packages/nx/** @vsavkin @FrozenPandaz @AgentEnder
|
||||
@@ -136,7 +138,7 @@ pnpm-lock.yaml @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
/packages/nx/** @vsavkin @FrozenPandaz @AgentEnder
|
||||
/packages/nx/src/adapter @AgentEnder @leosvelperez
|
||||
/packages/nx/src/native @vsavkin @FrozenPandaz @Cammisuli
|
||||
/packages/nx/src/lock-file @meeroslav @FrozenPandaz
|
||||
/packages/nx/src/plugins/js/lock-file @meeroslav @FrozenPandaz
|
||||
/packages/nx/src/nx-init/angular/** @Coly010 @leosvelperez @FrozenPandaz
|
||||
/e2e/nx-init/src/nx-init-angular.test.ts @Coly010 @leosvelperez
|
||||
/packages/nx/src/nx-init/react/** @jaysoo @xiongemi @mandarini
|
||||
@@ -170,7 +172,7 @@ pnpm-lock.yaml @FrozenPandaz @vsavkin @AgentEnder @jaysoo @JamesHenry
|
||||
# Global Files
|
||||
project.json @FrozenPandaz @vsavkin
|
||||
jest.config.ts @barbados-clemens @FrozenPandaz
|
||||
jest.preset.ts @barbados-clemens @FrozenPandaz
|
||||
jest.preset.js @barbados-clemens @FrozenPandaz
|
||||
|
||||
# Overrides - These are applied last, so override any matches above.
|
||||
docs/generated/manifests/* @bcabanes @FrozenPandaz @jaysoo @AgentEnder @isaacplmann @juristr
|
||||
|
||||
+3
-3
@@ -142,19 +142,19 @@ nx test jest
|
||||
To make sure your changes do not break any E2E tests, run:
|
||||
|
||||
```bash
|
||||
nx e2e e2e-cli # or any other project here
|
||||
nx e2e e2e-vite # or any other project here
|
||||
```
|
||||
|
||||
Running E2E tests can take some time, so it is often useful to run a single test. To run a single suite of tests, run:
|
||||
|
||||
```bash
|
||||
nx e2e e2e-cli -t versions # I often add qqqq to my test name so I can use -t qqqq
|
||||
nx e2e e2e-vite -t versions # I often add qqqq to my test name so I can use -t qqqq
|
||||
```
|
||||
|
||||
Sometimes tests pass locally but they fail on the CI. To reproduce the CI environment and be able to debug the issue, run:
|
||||
|
||||
```bash
|
||||
NX_VERBOSE_LOGGING=true CI=true SELECTED_PM=pnpm pnpm nx e2e e2e-cli --t="should do something is this test"
|
||||
NX_VERBOSE_LOGGING=true CI=true SELECTED_PM=pnpm pnpm nx e2e e2e-vite --t="should do something is this test"
|
||||
```
|
||||
|
||||
The above command sets verbose logging (this exposes stack traces and underlying errors), sets the defaults to be CI-like and sets Pnpm as the selected package manager.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Webpack Dev Server",
|
||||
"description": "The webpack-dev-server executor is very similar to the standard dev server builder provided by the Angular Devkit. It is usually used in tandem with `@nrwl/angular:webpack-browser` when your Angular application uses a custom webpack configuration.",
|
||||
"description": "The webpack-dev-server executor is very similar to the standard dev server builder provided by the Angular Devkit. It is usually used in tandem with `@nx/angular:webpack-browser` when your Angular application uses a custom webpack configuration.",
|
||||
"examplesFile": "##### Seving an application with a custom webpack configuration\n\nThis executor should be used along with `@nx/angular:webpack-browser` to serve an application using a custom webpack configuration.\n\nYour `project.json` file should contain a `build` and `serve` target that matches the following:\n\n```json\n\"build\": {\n \"executor\": \"@nx/angular:webpack-browser\",\n \"options\": {\n ...\n \"customWebpackConfig\": {\n \"path\": \"apps/appName/webpack.config.js\"\n }\n }\n},\n\"serve\": {\n \"executor\": \"@nx/angular:webpack-dev-server\",\n \"configurations\": {\n \"production\": {\n \"browserTarget\": \"appName:build:production\"\n },\n \"development\": {\n \"browserTarget\": \"appName:build:development\"\n }\n },\n \"defaultConfiguration\": \"development\",\n}\n```\n",
|
||||
"type": "object",
|
||||
"presets": [
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Webpack Server",
|
||||
"description": "The webpack-dev-server executor is very similar to the standard server builder provided by the Angular Devkit. It is usually used in tandem with `@nrwl/angular:webpack-browser` when your Angular application uses a custom webpack configuration and NgUniversal for SSR.",
|
||||
"description": "The webpack-dev-server executor is very similar to the standard server builder provided by the Angular Devkit. It is usually used in tandem with `@nx/angular:webpack-browser` when your Angular application uses a custom webpack configuration and NgUniversal for SSR.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"assets": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:add-linting --prefix=cool --projectName=cool-lib --projectRoot=libs/cool-lib",
|
||||
"command": "nx g @nx/angular:add-linting --prefix=cool --projectName=cool-lib --projectRoot=libs/cool-lib",
|
||||
"description": "Adds ESLint with Angular-specific rules for an existing project named `cool-lib` with the [prefix](https://angular.io/guide/styleguide#style-02-07) `cool`"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"additionalProperties": false,
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:convert-to-with-mf --project mf-app",
|
||||
"command": "nx g @nx/angular:convert-to-with-mf --project mf-app",
|
||||
"description": "Convert a Module Federation Project using legacy webpack config to use the `withModuleFederation` helper."
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:host appName --remotes=remote1",
|
||||
"command": "nx g @nx/angular:host appName --remotes=remote1",
|
||||
"description": "Create an Angular application with configuration in place for Module Federation. If the `remotes` option is provided, attach the remote application to this application's configuration"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
"$id": "SchematicsAngularModuleInit",
|
||||
"cli": "nx",
|
||||
"title": "Init Angular Plugin",
|
||||
"description": "Initializes the `@nrwl/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
||||
"description": "Initializes the `@nx/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:init --style=scss",
|
||||
"description": "Installs angular dependencies and initializes the `@nrwl/angular` plugin with the `scss` stylesheet format."
|
||||
"command": "nx g @nx/angular:init --style=scss",
|
||||
"description": "Installs angular dependencies and initializes the `@nx/angular` plugin with the `scss` stylesheet format."
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
@@ -31,7 +31,7 @@
|
||||
},
|
||||
"skipInstall": {
|
||||
"type": "boolean",
|
||||
"description": "Skip installing after adding `@nrwl/workspace`.",
|
||||
"description": "Skip installing after adding `@nx/workspace`.",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:move --project my-feature-lib --destination shared/my-feature-lib",
|
||||
"command": "nx g @nx/angular:move --project my-feature-lib --destination shared/my-feature-lib",
|
||||
"description": "Move libs/my-feature-lib to libs/shared/my-feature-lib."
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,19 +10,19 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:ngrx --root --parent=apps/my-app/src/app/app.module.ts --facade=false placeholder",
|
||||
"command": "nx g @nx/angular:ngrx --root --parent=apps/my-app/src/app/app.module.ts --facade=false placeholder",
|
||||
"description": "Add root ngrx configration to the `my-app` application"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/angular:ngrx --parent=libs/my-lib/src/lib/my-lib.module.ts --facade=true --root=false users",
|
||||
"command": "nx g @nx/angular:ngrx --parent=libs/my-lib/src/lib/my-lib.module.ts --facade=true --root=false users",
|
||||
"description": "Add a `users` state with a facade to the `my-lib` library. It will be tracked under the default `+state` folder in the lib"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/angular:ngrx --parent=apps/my-app/src/app/app.config.ts --root",
|
||||
"command": "nx g @nx/angular:ngrx --parent=apps/my-app/src/app/app.config.ts --root",
|
||||
"description": "Add a root state configuration to `my-app` when `my-app` uses Standalone APIs"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/angular:ngrx --parent=libs/my-lib/src/lib.routes.ts users",
|
||||
"command": "nx g @nx/angular:ngrx --parent=libs/my-lib/src/lib.routes.ts users",
|
||||
"description": "Add a `users` feature state to the Route definition of a library using Standalone APIs"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:remote appName --host=host --port=4201",
|
||||
"command": "nx g @nx/angular:remote appName --host=host --port=4201",
|
||||
"description": "Create an Angular app with configuration in place for Module Federation. If host is provided, attach this remote app to host app's configuration."
|
||||
}
|
||||
],
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:scam-directive --project=my-lib --flat=false my-sample",
|
||||
"command": "nx g @nx/angular:scam-directive --project=my-lib --flat=false my-sample",
|
||||
"description": "Generate a `MySampleDirective` directive in a `my-sample` folder in the `my-lib` library"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:scam-pipe --project=my-lib --flat=false my-transformation",
|
||||
"command": "nx g @nx/angular:scam-pipe --project=my-lib --flat=false my-transformation",
|
||||
"description": "Generates a `MyTransformationPipe` in a `my-transformation` folder in the `my-lib` project"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:scam --project=my-lib my-sample",
|
||||
"command": "nx g @nx/angular:scam --project=my-lib my-sample",
|
||||
"description": "Generate a `MySampleComponent` component in the `my-lib` library."
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/cypress:cypress-component-configuration --project=my-cool-lib ",
|
||||
"command": "nx g @nx/cypress:cypress-component-configuration --project=my-cool-lib ",
|
||||
"description": "Add cypress component testing to an existing project named my-cool-lib"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/cypress:migrate-to-cypress-11",
|
||||
"command": "nx g @nx/cypress:migrate-to-cypress-11",
|
||||
"description": "Migrate existing cypress projects to Cypress v11"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"framework": {
|
||||
"type": "string",
|
||||
"description": "App framework to test",
|
||||
"enum": ["react-native", "expo"],
|
||||
"default": "react-native"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
"description": "Run build locally [experimental]",
|
||||
"default": false
|
||||
},
|
||||
"output": {
|
||||
"type": "string",
|
||||
"description": "Output path for local build"
|
||||
},
|
||||
"wait": {
|
||||
"type": "boolean",
|
||||
"description": "Wait for build(s) to complete",
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
"description": "Create an Expo Application for Nx.",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g @nrwl/expo:app myapp --directory=nested",
|
||||
"command": "g @nx/expo:app myapp --directory=nested",
|
||||
"description": "Generate apps/nested/myapp"
|
||||
},
|
||||
{
|
||||
"command": "g @nrwl/expo:app myapp --classComponent",
|
||||
"command": "g @nx/expo:app myapp --classComponent",
|
||||
"description": "Use class components instead of functional components"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g @nrwl/expo:component my-component --project=mylib",
|
||||
"command": "g @nx/expo:component my-component --project=mylib",
|
||||
"description": "Generate a component in the mylib library"
|
||||
},
|
||||
{
|
||||
"command": "g @nrwl/expo:component my-component --project=mylib --classComponent",
|
||||
"command": "g @nx/expo:component my-component --project=mylib --classComponent",
|
||||
"description": "Generate a class component in the mylib library"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g @nrwl/expo:lib mylib --directory=myapp",
|
||||
"command": "g @nx/expo:lib mylib --directory=myapp",
|
||||
"description": "Generate libs/myapp/mylib"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -148,19 +148,52 @@ cleanupRegisteredPaths();
|
||||
|
||||
{% callout type="note" title="@swc/jest & global scripts" %}
|
||||
When using @swc/jest and a global setup/teardown file,
|
||||
You'll have to set the global setup/teardown file to be transformed with ts-jest.
|
||||
For example, if your files are named `global-setup.ts` and `global-teardown.ts`,
|
||||
then you would need to add to your _project level `jest.config.ts`_ a new entry in the transformers object
|
||||
You have to set the `noInterop: false` and use dynmamic imports within the setup function
|
||||
|
||||
```typescript {% fileName="apps/<your-project>/jest.config.ts" %}
|
||||
/* eslint-disable */
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
// Reading the SWC compilation config and remove the "exclude"
|
||||
// for the test files to be compiled by SWC
|
||||
const { exclude: _, ...swcJestConfig } = JSON.parse(
|
||||
readFileSync(`${__dirname}/.swcrc`, 'utf-8')
|
||||
);
|
||||
|
||||
// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
|
||||
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
|
||||
if (swcJestConfig.swcrc === undefined) {
|
||||
swcJestConfig.swcrc = false;
|
||||
}
|
||||
|
||||
// jest needs EsModule Interop to find the default exported function
|
||||
swcJestConfig.module.noInterop = false;
|
||||
|
||||
export default {
|
||||
globalSetup: '<rootDir>/src/global-setup-swc.ts',
|
||||
transform: {
|
||||
'global-(setup|teardown).ts': 'ts-jest',
|
||||
// resest of the transformers
|
||||
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
|
||||
},
|
||||
// other settings
|
||||
};
|
||||
```
|
||||
|
||||
```typescript {% fileName="global-setup-swc.ts" %}
|
||||
import { registerTsProject } from '@nx/js/src/internal';
|
||||
const cleanupRegisteredPaths = registerTsProject('.', 'tsconfig.base.json');
|
||||
|
||||
export default async function () {
|
||||
// swc will hoist all imports, and we need to make sure the register happens first
|
||||
// so we import all nx project alias within the setup function first.
|
||||
const { yourFancyFunction } = await import('@some-org/my-util-library');
|
||||
|
||||
yourFancyFunction();
|
||||
|
||||
// make sure to run the clean up!
|
||||
cleanupRegisteredPaths();
|
||||
}
|
||||
```
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## More Documentation
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "NxTypescriptInit",
|
||||
"cli": "nx",
|
||||
"title": "Init nrwl/js",
|
||||
"description": "Init generator placeholder for nrwl/js.",
|
||||
"title": "Init nx/js",
|
||||
"description": "Init generator placeholder for nx/js.",
|
||||
"properties": {
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/linter:workspace-rules-project",
|
||||
"command": "nx g @nx/linter:workspace-rules-project",
|
||||
"description": "Create the Workspace Lint Rules Project"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/next:cypress-component-configuration --project=my-next-project",
|
||||
"command": "nx g @nx/next:cypress-component-configuration --project=my-next-project",
|
||||
"description": "Add component testing to your Next project"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/next:cypress-component-configuration --project=my-next-project --generate-tests",
|
||||
"command": "nx g @nx/next:cypress-component-configuration --project=my-next-project --generate-tests",
|
||||
"description": "Add component testing to your Next project and generate component tests for your existing components"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"cli": "nx",
|
||||
"$id": "NxPluginPreset",
|
||||
"title": "Generator ran by create-nx-plugin",
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-plugin` or `create-nx-workspace --preset @nrwl/nx-plugin`.",
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-plugin` or `create-nx-workspace --preset @nx/nx-plugin`.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pluginName": {
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
"description": "Create a React Application for Nx.",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/react-native:app myapp --directory=nested",
|
||||
"command": "nx g @nx/react-native:app myapp --directory=nested",
|
||||
"description": "Generate `apps/nested/myapp`"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/react-native:app myapp --classComponent",
|
||||
"command": "nx g @nx/react-native:app myapp --classComponent",
|
||||
"description": "Use class components instead of functional components"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/react-native:component my-component --project=mylib",
|
||||
"command": "nx g @nx/react-native:component my-component --project=mylib",
|
||||
"description": "Generate a component in the `mylib` library"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/react-native:component my-component --project=mylib --classComponent",
|
||||
"command": "nx g @nx/react-native:component my-component --project=mylib --classComponent",
|
||||
"description": "Generate a class component in the `mylib` library"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/react-native:lib mylib --directory=myapp",
|
||||
"command": "nx g @nx/react-native:lib mylib --directory=myapp",
|
||||
"description": "Generate `libs/myapp/mylib`"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/react:component-test --project=my-react-project --component-path=src/lib/fancy-component.tsx",
|
||||
"command": "nx g @nx/react:component-test --project=my-react-project --component-path=src/lib/fancy-component.tsx",
|
||||
"description": "Create a cypress component test for FancyComponent"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/react:cypress-component-configuration --project=my-react-project",
|
||||
"command": "nx g @nx/react:cypress-component-configuration --project=my-react-project",
|
||||
"description": "Add component testing to your react project"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/react:cypress-component-configuration --project=my-react-project --generate-tests",
|
||||
"command": "nx g @nx/react:cypress-component-configuration --project=my-react-project --generate-tests",
|
||||
"description": "Add component testing to your react project and generate component tests for your existing components"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -159,6 +159,11 @@
|
||||
"type": "boolean",
|
||||
"description": "Generate package.json with 'exports' field. This field defines entry points in the package and is used by Node and the TypeScript compiler.",
|
||||
"default": false
|
||||
},
|
||||
"skipTypeCheck": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to skip TypeScript type checking.",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": ["tsConfig", "main", "outputPath"],
|
||||
|
||||
@@ -40,15 +40,15 @@
|
||||
},
|
||||
"buildTarget": {
|
||||
"type": "string",
|
||||
"description": "The build target of the project to be transformed to use the @nrwl/vite:build executor."
|
||||
"description": "The build target of the project to be transformed to use the @nx/vite:build executor."
|
||||
},
|
||||
"serveTarget": {
|
||||
"type": "string",
|
||||
"description": "The serve target of the project to be transformed to use the @nrwl/vite:dev-server and @nrwl/vite:preview-server executors."
|
||||
"description": "The serve target of the project to be transformed to use the @nx/vite:dev-server and @nrwl/vite:preview-server executors."
|
||||
},
|
||||
"testTarget": {
|
||||
"type": "string",
|
||||
"description": "The test target of the project to be transformed to use the @nrwl/vite:test executor."
|
||||
"description": "The test target of the project to be transformed to use the @nx/vite:test executor."
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
},
|
||||
"testTarget": {
|
||||
"type": "string",
|
||||
"description": "The test target of the project to be transformed to use the @nrwl/vite:test executor.",
|
||||
"description": "The test target of the project to be transformed to use the @nx/vite:test executor.",
|
||||
"hidden": true
|
||||
},
|
||||
"skipFormat": {
|
||||
|
||||
@@ -4,17 +4,17 @@
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "SchematicsConvertToNxProject",
|
||||
"title": "@nrwl/workspace:fix-configuration",
|
||||
"title": "@nx/workspace:fix-configuration",
|
||||
"description": "Migrates v1 config to v2 standalone configuration.",
|
||||
"type": "object",
|
||||
"cli": "nx",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/workspace:convert-to-nx-project --project my-feature-lib",
|
||||
"command": "nx g @nx/workspace:convert-to-nx-project --project my-feature-lib",
|
||||
"description": "Convert the `my-feature-lib` project to use `project.json` file instead of `workspace.json`"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/workspace:convert-to-nx-project --all",
|
||||
"command": "nx g @nx/workspace:convert-to-nx-project --all",
|
||||
"description": "Convert all projects in `workspace.json` to separate `project.json` files"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/workspace:move --project my-feature-lib --destination shared/my-feature-lib",
|
||||
"command": "nx g @nx/workspace:move --project my-feature-lib --destination shared/my-feature-lib",
|
||||
"description": "Move `libs/my-feature-lib` to `libs/shared/my-feature-lib`"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/workspace:remove my-feature-lib",
|
||||
"command": "nx g @nx/workspace:remove my-feature-lib",
|
||||
"description": "Remove `my-feature-lib` from the workspace"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/workspace:remove my-feature-lib --forceRemove",
|
||||
"command": "nx g @nx/workspace:remove my-feature-lib --forceRemove",
|
||||
"description": "Force removal of `my-feature-lib` from the workspace"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"cli": "nx",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/workspace:run-commands printhello --project my-feature-lib --command 'echo hello'",
|
||||
"command": "nx g @nx/workspace:run-commands printhello --project my-feature-lib --command 'echo hello'",
|
||||
"description": "Add the `printhello` target to `my-feature-lib`"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# React Native with Nx
|
||||
|
||||

|
||||
|
||||
Nx provides a holistic dev experience powered by an advanced CLI and editor plugins. It provides rich support for common tools like [Detox](/packages/detox), Storybook, Jest, and more.
|
||||
|
||||
In this guide we will show you how to develop [React Native](https://reactnative.dev/) applications with Nx.
|
||||
@@ -80,6 +78,10 @@ happynrwl/
|
||||
|
||||
To run the application in development mode:
|
||||
|
||||
```shell
|
||||
npx nx start mobile
|
||||
```
|
||||
|
||||
On Android simulator/device:
|
||||
|
||||
```shell
|
||||
@@ -96,7 +98,6 @@ Try out other commands as well.
|
||||
|
||||
- `nx lint mobile` to lint the application
|
||||
- `nx test mobile` to run unit test on the application using Jest
|
||||
- `nx serve mobile` to serve the application Javascript bundler that communicates with connected devices. This will start the bundler at http://localhost:8081.
|
||||
- `nx sync-deps mobile` to sync app dependencies to its `package.json`.
|
||||
|
||||
### Release build
|
||||
@@ -109,7 +110,9 @@ npx nx build-android mobile
|
||||
|
||||
**iOS:** (Mac only)
|
||||
|
||||
No CLI support yet. Run in the Xcode project. See: https://reactnative.dev/docs/running-on-device
|
||||
```shell
|
||||
npx nx build-ios mobile
|
||||
```
|
||||
|
||||
### E2E
|
||||
|
||||
@@ -125,7 +128,7 @@ npx nx test-android mobile-e2e
|
||||
npx nx test-ios mobile-e2e
|
||||
```
|
||||
|
||||
When using React Native in Nx, you get the out-of-the-box support for TypeScript, Detox, and Jest. No need to configure anything: watch mode, source maps, and typings just work.
|
||||
When using React Native in Nx, you get the out-of-the-box support for TypeScript, Detox, and Jest.
|
||||
|
||||
### Adding React Native to an Existing Workspace
|
||||
|
||||
@@ -258,40 +261,13 @@ dist/libs/shared-ui-layout/
|
||||
├── lib/
|
||||
│ └── layout/
|
||||
│ └── layout.d.ts
|
||||
├── package.json
|
||||
├── shared-ui-layout.esm.css
|
||||
├── shared-ui-layout.esm.js
|
||||
├── shared-ui-layout.umd.css
|
||||
└── shared-ui-layout.umd.js
|
||||
└── package.json
|
||||
```
|
||||
|
||||
This dist folder is ready to be published to a registry.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
The workspace should install[react-native-config](https://github.com/luggit/react-native-config) by default. To use environment variable, create a new `.env` file in the `happynrwl/apps/mobile` folder:
|
||||
|
||||
```
|
||||
NX_BUILD_NUMBER=123
|
||||
```
|
||||
|
||||
Then access variables defined there from your app:
|
||||
|
||||
```javascript
|
||||
import Config from 'react-native-config';
|
||||
|
||||
Config.NX_BUILD_NUMBER; // '123'
|
||||
```
|
||||
|
||||
## Code Sharing
|
||||
|
||||
Without Nx, creating a new shared library can take from several hours to even weeks: a new repo needs to be provisioned, CI needs to be set up, etc... In an Nx Workspace, it only takes minutes.
|
||||
|
||||
You can share React Native components between multiple React Native applications, share business logic code between React Native mobile applications and plain React web applications. You can even share code between the backend and the frontend. All of these can be done without any unnecessary ceremony.
|
||||
|
||||
## Resources
|
||||
|
||||
Here are other resources that you may find useful to learn more about React Native and Nx.
|
||||
|
||||
- **Blog post:** [Introducing React Native Support for Nx](https://blog.nrwl.io/introducing-react-native-support-for-nx-48d335e90c89) by Jack Hsu
|
||||
- **Blog post:** [Step by Step Guide on Creating a Monorepo for React Native Apps using Nx](https://blog.nrwl.io/step-by-step-guide-on-creating-a-monorepo-for-react-native-apps-using-nx-704753b6c70e) by Eimly Xiong
|
||||
|
||||
@@ -148,19 +148,52 @@ cleanupRegisteredPaths();
|
||||
|
||||
{% callout type="note" title="@swc/jest & global scripts" %}
|
||||
When using @swc/jest and a global setup/teardown file,
|
||||
You'll have to set the global setup/teardown file to be transformed with ts-jest.
|
||||
For example, if your files are named `global-setup.ts` and `global-teardown.ts`,
|
||||
then you would need to add to your _project level `jest.config.ts`_ a new entry in the transformers object
|
||||
You have to set the `noInterop: false` and use dynmamic imports within the setup function
|
||||
|
||||
```typescript {% fileName="apps/<your-project>/jest.config.ts" %}
|
||||
/* eslint-disable */
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
// Reading the SWC compilation config and remove the "exclude"
|
||||
// for the test files to be compiled by SWC
|
||||
const { exclude: _, ...swcJestConfig } = JSON.parse(
|
||||
readFileSync(`${__dirname}/.swcrc`, 'utf-8')
|
||||
);
|
||||
|
||||
// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
|
||||
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
|
||||
if (swcJestConfig.swcrc === undefined) {
|
||||
swcJestConfig.swcrc = false;
|
||||
}
|
||||
|
||||
// jest needs EsModule Interop to find the default exported function
|
||||
swcJestConfig.module.noInterop = false;
|
||||
|
||||
export default {
|
||||
globalSetup: '<rootDir>/src/global-setup-swc.ts',
|
||||
transform: {
|
||||
'global-(setup|teardown).ts': 'ts-jest',
|
||||
// resest of the transformers
|
||||
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
|
||||
},
|
||||
// other settings
|
||||
};
|
||||
```
|
||||
|
||||
```typescript {% fileName="global-setup-swc.ts" %}
|
||||
import { registerTsProject } from '@nx/js/src/internal';
|
||||
const cleanupRegisteredPaths = registerTsProject('.', 'tsconfig.base.json');
|
||||
|
||||
export default async function () {
|
||||
// swc will hoist all imports, and we need to make sure the register happens first
|
||||
// so we import all nx project alias within the setup function first.
|
||||
const { yourFancyFunction } = await import('@some-org/my-util-library');
|
||||
|
||||
yourFancyFunction();
|
||||
|
||||
// make sure to run the clean up!
|
||||
cleanupRegisteredPaths();
|
||||
}
|
||||
```
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## More Documentation
|
||||
|
||||
@@ -33,21 +33,27 @@ All other packages keep the same name, but change scope from `@nrwl` to `@nx`.
|
||||
| Nx 15 and lower | Nx 16 and higher |
|
||||
| ------------------ | ---------------- |
|
||||
| @nrwl/angular | @nx/angular |
|
||||
| @nrwl/aws-lambda | @nx/aws-lambda |
|
||||
| @nrwl/cypress | @nx/cypress |
|
||||
| @nrwl/deno | @nx/deno |
|
||||
| @nrwl/detox | @nx/detox |
|
||||
| @nrwl/devkit | @nx/devkit |
|
||||
| @nrwl/esbuild | @nx/esbuild |
|
||||
| @nrwl/expo | @nx/expo |
|
||||
| @nrwl/express | @nx/express |
|
||||
| @nrwl/gatsby | @nx/gatsby |
|
||||
| @nrwl/jest | @nx/jest |
|
||||
| @nrwl/js | @nx/js |
|
||||
| @nrwl/linter | @nx/linter |
|
||||
| @nrwl/nest | @nx/nest |
|
||||
| @nrwl/netlify | @nx/netlify |
|
||||
| @nrwl/next | @nx/next |
|
||||
| @nrwl/node | @nx/node |
|
||||
| @nrwl/react | @nx/react |
|
||||
| @nrwl/react-native | @nx/react-native |
|
||||
| @nrwl/remix | @nx/remix |
|
||||
| @nrwl/rollup | @nx/rollup |
|
||||
| @nrwl/rspack | @nx/rspack |
|
||||
| @nrwl/storybook | @nx/storybook |
|
||||
| @nrwl/vite | @nx/vite |
|
||||
| @nrwl/web | @nx/web |
|
||||
|
||||
@@ -232,7 +232,7 @@ describe('Linter', () => {
|
||||
import '@${projScope}/${invalidtaglib}';
|
||||
import '@${projScope}/${validtaglib}';
|
||||
|
||||
const s = {loadChildren: '@${projScope}/${lazylib}'};
|
||||
const s = {loadChildren: '@secondScope/${lazylib}'};
|
||||
`
|
||||
);
|
||||
|
||||
|
||||
@@ -177,6 +177,12 @@ describe('Next.js Applications', () => {
|
||||
`dist/packages/${appName}/public/shared/ui/hello.txt`
|
||||
);
|
||||
|
||||
// Check that compiled next config does not contain bad imports
|
||||
const nextConfigPath = `dist/packages/${appName}/next.config.js`;
|
||||
expect(nextConfigPath).not.toContain(`require("../`); // missing relative paths
|
||||
expect(nextConfigPath).not.toContain(`require("nx/`); // dev-only packages
|
||||
expect(nextConfigPath).not.toContain(`require("@nx/`); // dev-only packages
|
||||
|
||||
// Check that `nx serve <app> --prod` works with previous production build (e.g. `nx build <app>`).
|
||||
const prodServePort = 4000;
|
||||
const prodServeProcess = await runCommandUntil(
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"packages": ["build/packages/*", "build/packages/nx/native-packages/*"],
|
||||
"version": "16.1.0",
|
||||
"version": "16.1.4",
|
||||
"granularPathspec": false,
|
||||
"command": {
|
||||
"publish": {
|
||||
|
||||
+9
-9
@@ -11,6 +11,7 @@
|
||||
"check-imports": "node ./scripts/check-imports.js",
|
||||
"check-lock-files": "node ./scripts/check-lock-files.js",
|
||||
"check-documentation-map": "ts-node -P ./scripts/tsconfig.scripts.json ./scripts/documentation/map-link-checker.ts",
|
||||
"check-codeowners": "ts-node -P ./scripts/tsconfig.scripts.json ./scripts/check-codeowners.ts",
|
||||
"e2e-start-local-registry": "node ./scripts/e2e-start-local-registry.js",
|
||||
"e2e-build-package-publish": "ts-node -P ./scripts/tsconfig.e2e.json ./scripts/e2e-build-package-publish.ts",
|
||||
"nx-release": "ts-node -P ./scripts/tsconfig.release.json ./scripts/nx-release",
|
||||
@@ -48,8 +49,6 @@
|
||||
"@jest/reporters": "^29.4.1",
|
||||
"@jest/test-result": "^29.4.1",
|
||||
"@jest/types": "^29.4.1",
|
||||
"@lerna/publish": "6.0.0",
|
||||
"@lerna/version": "6.0.0",
|
||||
"@monodon/rust": "1.1.2",
|
||||
"@napi-rs/cli": "2.14.0",
|
||||
"@nestjs/cli": "^9.0.0",
|
||||
@@ -86,11 +85,11 @@
|
||||
"@rollup/plugin-node-resolve": "^13.0.4",
|
||||
"@rollup/plugin-url": "^7.0.0",
|
||||
"@schematics/angular": "~16.0.0",
|
||||
"@storybook/addon-essentials": "^7.0.8",
|
||||
"@storybook/core-server": "^7.0.8",
|
||||
"@storybook/react": "^7.0.8",
|
||||
"@storybook/react-webpack5": "^7.0.8",
|
||||
"@storybook/types": "^7.0.8",
|
||||
"@storybook/addon-essentials": "^7.0.9",
|
||||
"@storybook/core-server": "^7.0.9",
|
||||
"@storybook/react": "^7.0.9",
|
||||
"@storybook/react-webpack5": "^7.0.9",
|
||||
"@storybook/types": "^7.0.9",
|
||||
"@svgr/rollup": "^6.1.2",
|
||||
"@svgr/webpack": "^6.1.2",
|
||||
"@swc-node/register": "^1.4.2",
|
||||
@@ -194,7 +193,7 @@
|
||||
"jsonc-eslint-parser": "^2.1.0",
|
||||
"jsonc-parser": "3.2.0",
|
||||
"kill-port": "^1.6.1",
|
||||
"lerna": "6.0.0",
|
||||
"lerna": "6.6.2",
|
||||
"less": "4.1.3",
|
||||
"less-loader": "11.1.0",
|
||||
"license-webpack-plugin": "^4.0.2",
|
||||
@@ -311,7 +310,7 @@
|
||||
"history": "^5.3.0",
|
||||
"json-schema-to-typescript": "^10.1.5",
|
||||
"jsonpointer": "^5.0.0",
|
||||
"next": "13.1.1",
|
||||
"next": "13.3.4",
|
||||
"next-seo": "^5.13.0",
|
||||
"npm-run-path": "^4.0.1",
|
||||
"preact": "10.6.4",
|
||||
@@ -341,6 +340,7 @@
|
||||
"check-format",
|
||||
"check-imports",
|
||||
"check-lock-files",
|
||||
"check-codeowners",
|
||||
"depcheck",
|
||||
"documentation"
|
||||
]
|
||||
|
||||
@@ -1110,6 +1110,22 @@
|
||||
"alwaysAddToPackageJson": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"16.1.3-jest": {
|
||||
"version": "16.1.3-beta.0",
|
||||
"requires": {
|
||||
"@angular-devkit/build-angular": ">=13.0.0 <17.0.0",
|
||||
"@angular/compiler-cli": ">=13.0.0 <17.0.0",
|
||||
"@angular/core": ">=13.0.0 <17.0.0",
|
||||
"@angular/platform-browser-dynamic": ">=13.0.0 <17.0.0",
|
||||
"jest": "^29.0.0"
|
||||
},
|
||||
"packages": {
|
||||
"jest-preset-angular": {
|
||||
"version": "~13.1.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Webpack Dev Server",
|
||||
"description": "The webpack-dev-server executor is very similar to the standard dev server builder provided by the Angular Devkit. It is usually used in tandem with `@nrwl/angular:webpack-browser` when your Angular application uses a custom webpack configuration.",
|
||||
"description": "The webpack-dev-server executor is very similar to the standard dev server builder provided by the Angular Devkit. It is usually used in tandem with `@nx/angular:webpack-browser` when your Angular application uses a custom webpack configuration.",
|
||||
"examplesFile": "../../../docs/webpack-dev-server-examples.md",
|
||||
"type": "object",
|
||||
"presets": [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Webpack Server",
|
||||
"description": "The webpack-dev-server executor is very similar to the standard server builder provided by the Angular Devkit. It is usually used in tandem with `@nrwl/angular:webpack-browser` when your Angular application uses a custom webpack configuration and NgUniversal for SSR.",
|
||||
"description": "The webpack-dev-server executor is very similar to the standard server builder provided by the Angular Devkit. It is usually used in tandem with `@nx/angular:webpack-browser` when your Angular application uses a custom webpack configuration and NgUniversal for SSR.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"assets": {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:add-linting --prefix=cool --projectName=cool-lib --projectRoot=libs/cool-lib",
|
||||
"command": "nx g @nx/angular:add-linting --prefix=cool --projectName=cool-lib --projectRoot=libs/cool-lib",
|
||||
"description": "Adds ESLint with Angular-specific rules for an existing project named `cool-lib` with the [prefix](https://angular.io/guide/styleguide#style-02-07) `cool`"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import { Tree, joinPathFragments } from '@nx/devkit';
|
||||
import type { NormalizedSchema } from './normalized-schema';
|
||||
|
||||
import { jestProjectGenerator } from '@nx/jest';
|
||||
@@ -15,5 +15,24 @@ export async function addUnitTestRunner(host: Tree, options: NormalizedSchema) {
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
skipFormat: true,
|
||||
});
|
||||
const setupFile = joinPathFragments(
|
||||
options.appProjectRoot,
|
||||
'src',
|
||||
'test-setup.ts'
|
||||
);
|
||||
if (options.strict && host.exists(setupFile)) {
|
||||
const contents = host.read(setupFile, 'utf-8');
|
||||
host.write(
|
||||
setupFile,
|
||||
`// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment
|
||||
globalThis.ngJest = {
|
||||
testEnvironmentOptions: {
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
},
|
||||
};
|
||||
${contents}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"additionalProperties": false,
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:convert-to-with-mf --project mf-app",
|
||||
"command": "nx g @nx/angular:convert-to-with-mf --project mf-app",
|
||||
"description": "Convert a Module Federation Project using legacy webpack config to use the `withModuleFederation` helper."
|
||||
}
|
||||
],
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:host appName --remotes=remote1",
|
||||
"command": "nx g @nx/angular:host appName --remotes=remote1",
|
||||
"description": "Create an Angular application with configuration in place for Module Federation. If the `remotes` option is provided, attach the remote application to this application's configuration"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
"$id": "SchematicsAngularModuleInit",
|
||||
"cli": "nx",
|
||||
"title": "Init Angular Plugin",
|
||||
"description": "Initializes the `@nrwl/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
||||
"description": "Initializes the `@nx/angular` plugin. NOTE: Does not work in the `--dry-run` mode.",
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:init --style=scss",
|
||||
"description": "Installs angular dependencies and initializes the `@nrwl/angular` plugin with the `scss` stylesheet format."
|
||||
"command": "nx g @nx/angular:init --style=scss",
|
||||
"description": "Installs angular dependencies and initializes the `@nx/angular` plugin with the `scss` stylesheet format."
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
@@ -28,7 +28,7 @@
|
||||
},
|
||||
"skipInstall": {
|
||||
"type": "boolean",
|
||||
"description": "Skip installing after adding `@nrwl/workspace`.",
|
||||
"description": "Skip installing after adding `@nx/workspace`.",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
|
||||
@@ -134,6 +134,25 @@ async function addUnitTestRunner(
|
||||
skipFormat: true,
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
});
|
||||
const setupFile = joinPathFragments(
|
||||
options.projectRoot,
|
||||
'src',
|
||||
'test-setup.ts'
|
||||
);
|
||||
if (options.strict && host.exists(setupFile)) {
|
||||
const contents = host.read(setupFile, 'utf-8');
|
||||
host.write(
|
||||
setupFile,
|
||||
`// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment
|
||||
globalThis.ngJest = {
|
||||
testEnvironmentOptions: {
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
},
|
||||
};
|
||||
${contents}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:move --project my-feature-lib --destination shared/my-feature-lib",
|
||||
"command": "nx g @nx/angular:move --project my-feature-lib --destination shared/my-feature-lib",
|
||||
"description": "Move libs/my-feature-lib to libs/shared/my-feature-lib."
|
||||
}
|
||||
],
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { SourceFile } from 'typescript';
|
||||
import {
|
||||
addImportToModule,
|
||||
addProviderToAppConfig,
|
||||
addProviderToBootstrapApplication,
|
||||
addProviderToModule,
|
||||
} from '../../../utils/nx-devkit/ast-utils';
|
||||
import type { NormalizedNgRxGeneratorOptions } from './normalize-options';
|
||||
@@ -23,8 +24,11 @@ function addRootStoreImport(
|
||||
storeForRoot: string
|
||||
) {
|
||||
if (isParentStandalone) {
|
||||
if (tree.read(parentPath, 'utf-8').includes('ApplicationConfig')) {
|
||||
const parentContents = tree.read(parentPath, 'utf-8');
|
||||
if (parentContents.includes('ApplicationConfig')) {
|
||||
addProviderToAppConfig(tree, parentPath, provideRootStore);
|
||||
} else if (parentContents.includes('bootstrapApplication')) {
|
||||
addProviderToBootstrapApplication(tree, parentPath, provideRootStore);
|
||||
} else {
|
||||
addProviderToRoute(tree, parentPath, route, provideRootStore);
|
||||
}
|
||||
@@ -44,8 +48,11 @@ function addRootEffectsImport(
|
||||
effectsForEmptyRoot: string
|
||||
) {
|
||||
if (isParentStandalone) {
|
||||
if (tree.read(parentPath, 'utf-8').includes('ApplicationConfig')) {
|
||||
const parentContents = tree.read(parentPath, 'utf-8');
|
||||
if (parentContents.includes('ApplicationConfig')) {
|
||||
addProviderToAppConfig(tree, parentPath, provideRootEffects);
|
||||
} else if (parentContents.includes('bootstrapApplication')) {
|
||||
addProviderToBootstrapApplication(tree, parentPath, provideRootEffects);
|
||||
} else {
|
||||
addProviderToRoute(tree, parentPath, route, provideRootEffects);
|
||||
}
|
||||
@@ -91,8 +98,15 @@ function addStoreForFeatureImport(
|
||||
storeForFeature: string
|
||||
) {
|
||||
if (isParentStandalone) {
|
||||
if (tree.read(parentPath, 'utf-8').includes('ApplicationConfig')) {
|
||||
const parentContents = tree.read(parentPath, 'utf-8');
|
||||
if (parentContents.includes('ApplicationConfig')) {
|
||||
addProviderToAppConfig(tree, parentPath, provideStoreForFeature);
|
||||
} else if (parentContents.includes('bootstrapApplication')) {
|
||||
addProviderToBootstrapApplication(
|
||||
tree,
|
||||
parentPath,
|
||||
provideStoreForFeature
|
||||
);
|
||||
} else {
|
||||
addProviderToRoute(tree, parentPath, route, provideStoreForFeature);
|
||||
}
|
||||
@@ -117,8 +131,15 @@ function addEffectsForFeatureImport(
|
||||
effectsForFeature: string
|
||||
) {
|
||||
if (isParentStandalone) {
|
||||
if (tree.read(parentPath, 'utf-8').includes('ApplicationConfig')) {
|
||||
const parentContents = tree.read(parentPath, 'utf-8');
|
||||
if (parentContents.includes('ApplicationConfig')) {
|
||||
addProviderToAppConfig(tree, parentPath, provideEffectsForFeature);
|
||||
} else if (parentContents.includes('bootstrapApplication')) {
|
||||
addProviderToBootstrapApplication(
|
||||
tree,
|
||||
parentPath,
|
||||
provideEffectsForFeature
|
||||
);
|
||||
} else {
|
||||
addProviderToRoute(tree, parentPath, route, provideEffectsForFeature);
|
||||
}
|
||||
|
||||
@@ -7,19 +7,19 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:ngrx --root --parent=apps/my-app/src/app/app.module.ts --facade=false placeholder",
|
||||
"command": "nx g @nx/angular:ngrx --root --parent=apps/my-app/src/app/app.module.ts --facade=false placeholder",
|
||||
"description": "Add root ngrx configration to the `my-app` application"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/angular:ngrx --parent=libs/my-lib/src/lib/my-lib.module.ts --facade=true --root=false users",
|
||||
"command": "nx g @nx/angular:ngrx --parent=libs/my-lib/src/lib/my-lib.module.ts --facade=true --root=false users",
|
||||
"description": "Add a `users` state with a facade to the `my-lib` library. It will be tracked under the default `+state` folder in the lib"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/angular:ngrx --parent=apps/my-app/src/app/app.config.ts --root",
|
||||
"command": "nx g @nx/angular:ngrx --parent=apps/my-app/src/app/app.config.ts --root",
|
||||
"description": "Add a root state configuration to `my-app` when `my-app` uses Standalone APIs"
|
||||
},
|
||||
{
|
||||
"command": "nx g @nrwl/angular:ngrx --parent=libs/my-lib/src/lib.routes.ts users",
|
||||
"command": "nx g @nx/angular:ngrx --parent=libs/my-lib/src/lib.routes.ts users",
|
||||
"description": "Add a `users` feature state to the Route definition of a library using Standalone APIs"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:remote appName --host=host --port=4201",
|
||||
"command": "nx g @nx/angular:remote appName --host=host --port=4201",
|
||||
"description": "Create an Angular app with configuration in place for Module Federation. If host is provided, attach this remote app to host app's configuration."
|
||||
}
|
||||
],
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:scam-directive --project=my-lib --flat=false my-sample",
|
||||
"command": "nx g @nx/angular:scam-directive --project=my-lib --flat=false my-sample",
|
||||
"description": "Generate a `MySampleDirective` directive in a `my-sample` folder in the `my-lib` library"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:scam-pipe --project=my-lib --flat=false my-transformation",
|
||||
"command": "nx g @nx/angular:scam-pipe --project=my-lib --flat=false my-transformation",
|
||||
"description": "Generates a `MyTransformationPipe` in a `my-transformation` folder in the `my-lib` project"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/angular:scam --project=my-lib my-sample",
|
||||
"command": "nx g @nx/angular:scam --project=my-lib my-sample",
|
||||
"description": "Generate a `MySampleComponent` component in the `my-lib` library."
|
||||
}
|
||||
],
|
||||
|
||||
@@ -25,6 +25,6 @@ export const postcssUrlVersion = '~10.1.3';
|
||||
export const autoprefixerVersion = '^10.4.0';
|
||||
export const tsNodeVersion = '10.9.1';
|
||||
|
||||
export const jestPresetAngularVersion = '~13.0.0';
|
||||
export const jestPresetAngularVersion = '~13.1.0';
|
||||
export const typesNodeVersion = '16.11.7';
|
||||
export const jasmineMarblesVersion = '^0.9.2';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/cypress:cypress-component-configuration --project=my-cool-lib ",
|
||||
"command": "nx g @nx/cypress:cypress-component-configuration --project=my-cool-lib ",
|
||||
"description": "Add cypress component testing to an existing project named my-cool-lib"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "nx g @nrwl/cypress:migrate-to-cypress-11",
|
||||
"command": "nx g @nx/cypress:migrate-to-cypress-11",
|
||||
"description": "Migrate existing cypress projects to Cypress v11"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
"version": "16.0.0-beta.3",
|
||||
"description": "Update .detoxrc.json and jest.config.json for detox 20",
|
||||
"implementation": "./src/migrations/update-16-0-0/update-detoxrc-json"
|
||||
},
|
||||
"update-detoxrc-json-expo-16-1-4": {
|
||||
"cli": "nx",
|
||||
"version": "16.1.4-beta.0",
|
||||
"description": "Update .detoxrc.json for expo",
|
||||
"implementation": "./src/migrations/update-16-1-4/update-detoxrc-json-expo"
|
||||
}
|
||||
},
|
||||
"packageJsonUpdates": {
|
||||
@@ -222,6 +228,19 @@
|
||||
"alwaysAddToPackageJson": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"16.1.1": {
|
||||
"version": "16.1.1-beta.0",
|
||||
"packages": {
|
||||
"detox": {
|
||||
"version": "~20.8.0",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@config-plugins/detox": {
|
||||
"version": "~5.0.1",
|
||||
"alwaysAddToPackageJson": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@nx/react": "file:../react"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"detox": "~20.7.0"
|
||||
"detox": "~20.8.0"
|
||||
},
|
||||
"builders": "./executors.json",
|
||||
"ng-update": {
|
||||
|
||||
@@ -345,14 +345,14 @@ describe('detox application generator', () => {
|
||||
'android.eas': {
|
||||
binaryPath: '../../../my-dir/my-app/dist/MyDirMyApp.apk',
|
||||
build:
|
||||
'npx nx run my-dir-my-app:download --platform android --output=my-dir/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
'npx nx run my-dir-my-app:download --platform android --output=../../../my-dir/my-app/dist/',
|
||||
type: 'android.apk',
|
||||
},
|
||||
'android.local': {
|
||||
binaryPath: '../../../my-dir/my-app/dist/MyDirMyApp.apk',
|
||||
build:
|
||||
'npx nx run my-dir-my-app:build --platform android --profile preview --wait --local --no-interactive --output=my-dir/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
'npx nx run my-dir-my-app:build --platform android --profile preview --wait --local --no-interactive --output=../../../my-dir/my-app/dist/MyDirMyApp.apk',
|
||||
type: 'android.apk',
|
||||
},
|
||||
'android.release': {
|
||||
binaryPath:
|
||||
@@ -371,13 +371,13 @@ describe('detox application generator', () => {
|
||||
'ios.eas': {
|
||||
binaryPath: '../../../my-dir/my-app/dist/MyDirMyApp.app',
|
||||
build:
|
||||
'npx nx run my-dir-my-app:download --platform ios --distribution simulator --output=my-dir/my-app/dist/',
|
||||
'npx nx run my-dir-my-app:download --platform ios --distribution simulator --output=../../../my-dir/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
},
|
||||
'ios.local': {
|
||||
binaryPath: '../../../my-dir/my-app/dist/MyDirMyApp.app',
|
||||
build:
|
||||
'npx nx run my-dir-my-app:build --platform ios --profile preview --wait --local --no-interactive --output=my-dir/my-app/dist/',
|
||||
'npx nx run my-dir-my-app:build --platform ios --profile preview --wait --local --no-interactive --output=../../../my-dir/my-app/dist/MyDirMyApp.tar.gz',
|
||||
type: 'ios.app',
|
||||
},
|
||||
'ios.release': {
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
<% if (framework === 'expo') { %>
|
||||
"ios.eas": {
|
||||
"type": "ios.app",
|
||||
"build": "<%= exec %> nx run <%= appFileName %>:download --platform ios --distribution simulator --output=<%= appRoot %>/dist/",
|
||||
"build": "<%= exec %> nx run <%= appFileName %>:download --platform ios --distribution simulator --output=<%= offsetFromRoot %><%= appRoot %>/dist/",
|
||||
"binaryPath": "<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.app"
|
||||
},
|
||||
"ios.local": {
|
||||
"type": "ios.app",
|
||||
"build": "<%= exec %> nx run <%= appFileName %>:build --platform ios --profile preview --wait --local --no-interactive --output=<%= appRoot %>/dist/",
|
||||
"build": "<%= exec %> nx run <%= appFileName %>:build --platform ios --profile preview --wait --local --no-interactive --output=<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.tar.gz",
|
||||
"binaryPath": "<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.app"
|
||||
},
|
||||
<% } %>
|
||||
@@ -43,13 +43,13 @@
|
||||
},
|
||||
<% if (framework === 'expo') { %>
|
||||
"android.eas": {
|
||||
"type": "ios.app",
|
||||
"build": "<%= exec %> nx run <%= appFileName %>:download --platform android --output=<%= appRoot %>/dist/",
|
||||
"type": "android.apk",
|
||||
"build": "<%= exec %> nx run <%= appFileName %>:download --platform android --output=<%= offsetFromRoot %><%= appRoot %>/dist/",
|
||||
"binaryPath": "<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.apk"
|
||||
},
|
||||
"android.local": {
|
||||
"type": "ios.app",
|
||||
"build": "<%= exec %> nx run <%= appFileName %>:build --platform android --profile preview --wait --local --no-interactive --output=<%= appRoot %>/dist/",
|
||||
"type": "android.apk",
|
||||
"build": "<%= exec %> nx run <%= appFileName %>:build --platform android --profile preview --wait --local --no-interactive --output=<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.apk",
|
||||
"binaryPath": "<%= offsetFromRoot %><%= appRoot %>/dist/<%= appExpoName %>.apk"
|
||||
},
|
||||
<% } %>
|
||||
@@ -97,11 +97,11 @@
|
||||
},
|
||||
<% if (framework === 'expo') { %>
|
||||
"android.emu.eas": {
|
||||
"device": "simulator",
|
||||
"device": "emulator",
|
||||
"app": "android.eas"
|
||||
},
|
||||
"android.emu.local": {
|
||||
"device": "simulator",
|
||||
"device": "emulator",
|
||||
"app": "android.local"
|
||||
},
|
||||
<% } %>
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { expoBuildTarget, expoTestTarget } from './get-targets';
|
||||
|
||||
describe('getTargets', () => {
|
||||
it('should return ios test target for expo projects', () => {
|
||||
expect(expoTestTarget('ios.sim', 'test')).toEqual({
|
||||
options: {
|
||||
detoxConfiguration: 'ios.sim.eas',
|
||||
buildTarget: 'test:build-ios',
|
||||
},
|
||||
configurations: {
|
||||
local: {
|
||||
detoxConfiguration: 'ios.sim.local',
|
||||
buildTarget: 'test:build-ios:local',
|
||||
},
|
||||
bare: {
|
||||
detoxConfiguration: 'ios.sim.debug',
|
||||
buildTarget: 'test:build-ios:bare',
|
||||
},
|
||||
production: {
|
||||
detoxConfiguration: 'ios.sim.release',
|
||||
buildTarget: 'test:build-ios:production',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return ios build target for expo projects', () => {
|
||||
expect(expoBuildTarget('ios.sim')).toEqual({
|
||||
options: {
|
||||
detoxConfiguration: 'ios.sim.eas',
|
||||
},
|
||||
configurations: {
|
||||
local: {
|
||||
detoxConfiguration: 'ios.sim.local',
|
||||
},
|
||||
bare: {
|
||||
detoxConfiguration: 'ios.sim.debug',
|
||||
},
|
||||
production: {
|
||||
detoxConfiguration: 'ios.sim.release',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -14,7 +14,7 @@ export function reactNativeBuildTarget(platform: 'ios.sim' | 'android.emu') {
|
||||
export function expoBuildTarget(platform: 'ios.sim' | 'android.emu') {
|
||||
return {
|
||||
options: {
|
||||
detoxConfiguration: `${platform}.debug`,
|
||||
detoxConfiguration: `${platform}.eas`,
|
||||
},
|
||||
configurations: {
|
||||
local: {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { jestVersion, typesNodeVersion } from '@nx/jest/src/utils/versions';
|
||||
|
||||
import { Schema } from './schema';
|
||||
import {
|
||||
configPluginsDetoxVersion,
|
||||
detoxVersion,
|
||||
nxVersion,
|
||||
testingLibraryJestDom,
|
||||
@@ -21,7 +22,7 @@ export async function detoxInitGenerator(host: Tree, schema: Schema) {
|
||||
|
||||
if (!schema.skipPackageJson) {
|
||||
tasks.push(moveDependency(host));
|
||||
tasks.push(updateDependencies(host));
|
||||
tasks.push(updateDependencies(host, schema));
|
||||
}
|
||||
|
||||
if (!schema.skipFormat) {
|
||||
@@ -31,7 +32,7 @@ export async function detoxInitGenerator(host: Tree, schema: Schema) {
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export function updateDependencies(host: Tree) {
|
||||
export function updateDependencies(host: Tree, schema: Schema) {
|
||||
return addDependenciesToPackageJson(
|
||||
host,
|
||||
{},
|
||||
@@ -41,6 +42,9 @@ export function updateDependencies(host: Tree) {
|
||||
'@testing-library/jest-dom': testingLibraryJestDom,
|
||||
'@types/node': typesNodeVersion,
|
||||
'jest-circus': jestVersion,
|
||||
...(schema.framework === 'expo'
|
||||
? { '@config-plugins/detox': configPluginsDetoxVersion }
|
||||
: {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export interface Schema {
|
||||
skipFormat?: boolean;
|
||||
skipPackageJson?: boolean; //default is false
|
||||
framework?: 'react-native' | 'expo';
|
||||
}
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
"default": false,
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"framework": {
|
||||
"type": "string",
|
||||
"description": "App framework to test",
|
||||
"enum": ["react-native", "expo"],
|
||||
"default": "react-native"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('Update detoxrc for detox 20', () => {
|
||||
sourceRoot: 'apps/products/src',
|
||||
targets: {
|
||||
'test-ios': {
|
||||
executor: '@nrwl/detox:test',
|
||||
executor: '@nx/detox:test',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -31,6 +31,10 @@ describe('Update detoxrc for detox 20', () => {
|
||||
'<rootDir>/src/**/*.test.ts?(x)',
|
||||
'<rootDir>/src/**/*.spec.ts?(x)',
|
||||
],
|
||||
globalSetup: 'detox/runners/jest/globalSetup',
|
||||
globalTeardown: 'detox/runners/jest/globalTeardown',
|
||||
reporter: ['detox/runners/jest/reporter'],
|
||||
verbose: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@ import {
|
||||
* - update keys: runnerConfig
|
||||
* Update jest.config.json under detox project:
|
||||
* - remove key: transform
|
||||
* - add key: rootDir, testMatch
|
||||
* - add key: rootDir, testMatch, reporter, globalSetup, globalTeardown, verbose
|
||||
*/
|
||||
export default async function update(tree: Tree) {
|
||||
const projects = getProjects(tree);
|
||||
|
||||
projects.forEach((project) => {
|
||||
if (project.targets?.['test-ios']?.executor !== '@nrwl/detox:test') return;
|
||||
if (project.targets?.['test-ios']?.executor !== '@nx/detox:test') return;
|
||||
updateDetoxrcJson(tree, project);
|
||||
updateJestConfigJson(tree, project);
|
||||
});
|
||||
@@ -62,6 +62,10 @@ function updateJestConfigJson(host: Tree, project: ProjectConfiguration) {
|
||||
'<rootDir>/src/**/*.spec.ts?(x)',
|
||||
];
|
||||
}
|
||||
json.reporter = ['detox/runners/jest/reporter'];
|
||||
json.globalSetup = 'detox/runners/jest/globalSetup';
|
||||
json.globalTeardown = 'detox/runners/jest/globalTeardown';
|
||||
json.verbose = true;
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import { addProjectConfiguration, readJson, Tree } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
|
||||
import update from './update-detoxrc-json-expo';
|
||||
|
||||
describe('Update detoxrc for expo projects', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(async () => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
addProjectConfiguration(tree, 'products', {
|
||||
root: 'apps/products',
|
||||
sourceRoot: 'apps/products/src',
|
||||
targets: {
|
||||
'test-ios': {
|
||||
executor: '@nx/detox:test',
|
||||
options: {
|
||||
detoxConfiguration: 'ios.sim.eas',
|
||||
},
|
||||
},
|
||||
'build-ios': {
|
||||
executor: '@nx/detox:build',
|
||||
options: {
|
||||
detoxConfiguration: 'random value',
|
||||
},
|
||||
},
|
||||
'test-android': {
|
||||
executor: '@nx/detox:test',
|
||||
options: {
|
||||
detoxConfiguration: 'android.sim.eas',
|
||||
},
|
||||
},
|
||||
'build-android': {
|
||||
executor: '@nx/detox:build',
|
||||
options: {
|
||||
detoxConfiguration: 'random value',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
tree.write('apps/products/jest.config.json', `{"transform": {}}`);
|
||||
tree.write(
|
||||
'apps/products/.detoxrc.json',
|
||||
`{"apps": {"ios.eas": {}, "android.eas": {}, "ios.local": {}, "android.local": {}}}`
|
||||
);
|
||||
});
|
||||
|
||||
it(`should update .detoxrc.json`, async () => {
|
||||
await update(tree);
|
||||
|
||||
const detoxrcJson = readJson(tree, 'apps/products/.detoxrc.json');
|
||||
expect(detoxrcJson).toEqual({
|
||||
apps: {
|
||||
'ios.eas': {
|
||||
build:
|
||||
'npx nx run products:download --platform ios --distribution simulator --output=../../apps/products/dist/',
|
||||
},
|
||||
'android.eas': {
|
||||
build:
|
||||
'npx nx run products:download --platform android --distribution simulator --output=../../apps/products/dist/',
|
||||
type: 'android.apk',
|
||||
},
|
||||
'ios.local': {
|
||||
build:
|
||||
'npx nx run products:build --platform ios --configuration=debug --output=../../apps/products/dist/Products.tar.gz',
|
||||
},
|
||||
'android.local': {
|
||||
build:
|
||||
'npx nx run products:build --platform android --configuration=debug --output=../../apps/products/dist/Products.apk',
|
||||
type: 'android.apk',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it(`should update project.json`, async () => {
|
||||
await update(tree);
|
||||
|
||||
const projectJson = readJson(tree, 'apps/products/project.json');
|
||||
expect(projectJson).toEqual({
|
||||
$schema: '../../node_modules/nx/schemas/project-schema.json',
|
||||
name: 'products',
|
||||
sourceRoot: 'apps/products/src',
|
||||
targets: {
|
||||
'build-android': {
|
||||
executor: '@nx/detox:build',
|
||||
options: {
|
||||
detoxConfiguration: 'android.sim.eas',
|
||||
},
|
||||
},
|
||||
'build-ios': {
|
||||
executor: '@nx/detox:build',
|
||||
options: {
|
||||
detoxConfiguration: 'ios.sim.eas',
|
||||
},
|
||||
},
|
||||
'test-android': {
|
||||
configurations: {
|
||||
bare: {
|
||||
buildTarget: 'products:build-android:bare',
|
||||
detoxConfiguration: 'android.emu.debug',
|
||||
},
|
||||
local: {
|
||||
buildTarget: 'products:build-android:local',
|
||||
detoxConfiguration: 'android.emu.local',
|
||||
},
|
||||
production: {
|
||||
buildTarget: 'products:build-android:production',
|
||||
detoxConfiguration: 'android.emu.release',
|
||||
},
|
||||
},
|
||||
executor: '@nx/detox:test',
|
||||
options: {
|
||||
buildTarget: 'products:build-android',
|
||||
detoxConfiguration: 'android.sim.eas',
|
||||
},
|
||||
},
|
||||
'test-ios': {
|
||||
executor: '@nx/detox:test',
|
||||
options: {
|
||||
detoxConfiguration: 'ios.sim.eas',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
import {
|
||||
Tree,
|
||||
formatFiles,
|
||||
getProjects,
|
||||
updateJson,
|
||||
ProjectConfiguration,
|
||||
offsetFromRoot,
|
||||
detectPackageManager,
|
||||
getPackageManagerCommand,
|
||||
names,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
|
||||
/**
|
||||
* Update .detoxrc.json under detox project for expo:
|
||||
* - fix the eas build command
|
||||
* - fix the local build command
|
||||
* - update project.json targets
|
||||
*/
|
||||
export default async function update(tree: Tree) {
|
||||
const projects = getProjects(tree);
|
||||
|
||||
projects.forEach((project) => {
|
||||
if (project.targets?.['test-ios']?.executor !== '@nx/detox:test') return;
|
||||
updateDetoxrcJson(tree, project);
|
||||
updateProjectJson(tree, project);
|
||||
});
|
||||
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
function updateDetoxrcJson(host: Tree, project: ProjectConfiguration) {
|
||||
const detoxConfigPath = `${project.root}/.detoxrc.json`;
|
||||
const projectName = project.name;
|
||||
const appName = names(projectName).className;
|
||||
const offset = offsetFromRoot(project.root);
|
||||
const exec = getPackageManagerCommand(detectPackageManager(host.root)).exec;
|
||||
if (!host.exists(detoxConfigPath)) return;
|
||||
updateJson(host, detoxConfigPath, (json) => {
|
||||
if (json.apps?.['ios.eas']) {
|
||||
json.apps[
|
||||
'ios.eas'
|
||||
].build = `${exec} nx run ${projectName}:download --platform ios --distribution simulator --output=${offset}${project.root}/dist/`;
|
||||
}
|
||||
if (json.apps?.['android.eas']) {
|
||||
json.apps[
|
||||
'android.eas'
|
||||
].build = `${exec} nx run ${projectName}:download --platform android --distribution simulator --output=${offset}${project.root}/dist/`;
|
||||
json.apps['android.eas'].type = 'android.apk';
|
||||
}
|
||||
if (json.apps?.['ios.local']) {
|
||||
json.apps[
|
||||
'ios.local'
|
||||
].build = `${exec} nx run ${projectName}:build --platform ios --configuration=debug --output=${offset}${project.root}/dist/${appName}.tar.gz`;
|
||||
}
|
||||
if (json.apps?.['android.local']) {
|
||||
json.apps[
|
||||
'android.local'
|
||||
].build = `${exec} nx run ${projectName}:build --platform android --configuration=debug --output=${offset}${project.root}/dist/${appName}.apk`;
|
||||
json.apps['android.local'].type = 'android.apk';
|
||||
}
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
function updateProjectJson(host: Tree, project: ProjectConfiguration) {
|
||||
if (
|
||||
project.targets?.['test-ios']?.options?.detoxConfiguration == 'ios.sim.eas'
|
||||
) {
|
||||
project.targets['build-ios'].options.detoxConfiguration = 'ios.sim.eas';
|
||||
}
|
||||
if (
|
||||
project.targets?.['test-android']?.options?.detoxConfiguration ==
|
||||
'android.sim.eas'
|
||||
) {
|
||||
project.targets['build-android'].options.detoxConfiguration =
|
||||
'android.sim.eas';
|
||||
project.targets['test-android'] = {
|
||||
executor: '@nx/detox:test',
|
||||
options: {
|
||||
detoxConfiguration: 'android.sim.eas',
|
||||
buildTarget: `${project.name}:build-android`,
|
||||
},
|
||||
configurations: {
|
||||
local: {
|
||||
detoxConfiguration: 'android.emu.local',
|
||||
buildTarget: `${project.name}:build-android:local`,
|
||||
},
|
||||
bare: {
|
||||
detoxConfiguration: 'android.emu.debug',
|
||||
buildTarget: `${project.name}:build-android:bare`,
|
||||
},
|
||||
production: {
|
||||
detoxConfiguration: 'android.emu.release',
|
||||
buildTarget: `${project.name}:build-android:production`,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
updateProjectConfiguration(host, project.name, project);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export const nxVersion = require('../../package.json').version;
|
||||
|
||||
export const detoxVersion = '~20.7.0';
|
||||
export const detoxVersion = '~20.8.0';
|
||||
export const testingLibraryJestDom = '5.16.5';
|
||||
export const configPluginsDetoxVersion = '~5.0.1'; // only required for expo
|
||||
|
||||
@@ -29,28 +29,28 @@ export async function formatFiles(tree: Tree): Promise<void> {
|
||||
|
||||
await Promise.all(
|
||||
Array.from(files).map(async (file) => {
|
||||
const systemPath = path.join(tree.root, file.path);
|
||||
|
||||
const resolvedOptions = await prettier.resolveConfig(systemPath, {
|
||||
editorconfig: true,
|
||||
});
|
||||
|
||||
const options: Prettier.Options = {
|
||||
...resolvedOptions,
|
||||
...changedPrettierInTree,
|
||||
filepath: systemPath,
|
||||
};
|
||||
|
||||
if (file.path.endsWith('.swcrc')) {
|
||||
options.parser = 'json';
|
||||
}
|
||||
|
||||
const support = await prettier.getFileInfo(systemPath, options as any);
|
||||
if (support.ignored || !support.inferredParser) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const systemPath = path.join(tree.root, file.path);
|
||||
|
||||
const resolvedOptions = await prettier.resolveConfig(systemPath, {
|
||||
editorconfig: true,
|
||||
});
|
||||
|
||||
const options: Prettier.Options = {
|
||||
...resolvedOptions,
|
||||
...changedPrettierInTree,
|
||||
filepath: systemPath,
|
||||
};
|
||||
|
||||
if (file.path.endsWith('.swcrc')) {
|
||||
options.parser = 'json';
|
||||
}
|
||||
|
||||
const support = await prettier.getFileInfo(systemPath, options as any);
|
||||
if (support.ignored || !support.inferredParser) {
|
||||
return;
|
||||
}
|
||||
|
||||
tree.write(
|
||||
file.path,
|
||||
prettier.format(file.content.toString('utf-8'), options)
|
||||
|
||||
@@ -18,6 +18,7 @@ export function visitNotIgnoredFiles(
|
||||
ig.add(tree.read('.gitignore', 'utf-8'));
|
||||
}
|
||||
if (tree.exists('.nxignore')) {
|
||||
ig ??= ignore();
|
||||
ig.add(tree.read('.nxignore', 'utf-8'));
|
||||
}
|
||||
dirPath = normalizePathRelativeToRoot(dirPath, tree.root);
|
||||
|
||||
@@ -165,6 +165,14 @@ describe('replaceNrwlPackageWithNxPackage', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle broken package.json files', () => {
|
||||
tree.write('package.json', '{ broken: "json ');
|
||||
|
||||
expect(() =>
|
||||
replaceNrwlPackageWithNxPackage(tree, 'old-package', 'new-package')
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it('should replace any mentions in files', () => {
|
||||
expect(tree.read('README.txt').toString()).toContain('new-package');
|
||||
expect(tree.read('README.txt').toString()).not.toContain('old-package');
|
||||
|
||||
@@ -4,6 +4,7 @@ import { requireNx } from '../../nx';
|
||||
import { visitNotIgnoredFiles } from '../generators/visit-not-ignored-files';
|
||||
import { basename } from 'path';
|
||||
import { isBinaryPath } from './binary-extensions';
|
||||
const { logger } = requireNx();
|
||||
|
||||
const {
|
||||
getProjects,
|
||||
@@ -37,20 +38,26 @@ function replacePackageInDependencies(
|
||||
return;
|
||||
}
|
||||
|
||||
updateJson<PackageJson>(tree, path, (packageJson) => {
|
||||
for (const deps of [
|
||||
packageJson.dependencies ?? {},
|
||||
packageJson.devDependencies ?? {},
|
||||
packageJson.peerDependencies ?? {},
|
||||
packageJson.optionalDependencies ?? {},
|
||||
]) {
|
||||
if (oldPackageName in deps) {
|
||||
deps[newPackageName] = deps[oldPackageName];
|
||||
delete deps[oldPackageName];
|
||||
try {
|
||||
updateJson<PackageJson>(tree, path, (packageJson) => {
|
||||
for (const deps of [
|
||||
packageJson.dependencies ?? {},
|
||||
packageJson.devDependencies ?? {},
|
||||
packageJson.peerDependencies ?? {},
|
||||
packageJson.optionalDependencies ?? {},
|
||||
]) {
|
||||
if (oldPackageName in deps) {
|
||||
deps[newPackageName] = deps[oldPackageName];
|
||||
delete deps[oldPackageName];
|
||||
}
|
||||
}
|
||||
}
|
||||
return packageJson;
|
||||
});
|
||||
return packageJson;
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
`Could not replace ${oldPackageName} with ${newPackageName} in ${path}.`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -162,15 +169,23 @@ function replaceMentions(
|
||||
return;
|
||||
}
|
||||
|
||||
const contents = tree.read(path).toString();
|
||||
try {
|
||||
const contents = tree.read(path).toString();
|
||||
|
||||
if (!contents.includes(oldPackageName)) {
|
||||
return;
|
||||
if (!contents.includes(oldPackageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tree.write(
|
||||
path,
|
||||
contents.replace(new RegExp(oldPackageName, 'g'), newPackageName)
|
||||
);
|
||||
} catch {
|
||||
// Its **probably** ok, contents can be null if the file is too large or
|
||||
// there was an access exception.
|
||||
logger.warn(
|
||||
`An error was thrown when trying to update ${path}. If you believe the migration should have updated it, be sure to review the file and open an issue.`
|
||||
);
|
||||
}
|
||||
|
||||
tree.write(
|
||||
path,
|
||||
contents.replace(new RegExp(oldPackageName, 'g'), newPackageName)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import { findNodes } from '@nx/js';
|
||||
import { getModifiers } from '@typescript-eslint/type-utils';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { existsSync, lstatSync, readdirSync, readFileSync } from 'fs';
|
||||
import { dirname } from 'path';
|
||||
import ts = require('typescript');
|
||||
|
||||
@@ -81,6 +81,16 @@ function hasMemberExport(exportedMember, filePath) {
|
||||
}
|
||||
|
||||
export function getRelativeImportPath(exportedMember, filePath, basePath) {
|
||||
if (lstatSync(filePath).isDirectory()) {
|
||||
const file = readdirSync(filePath).find((file) =>
|
||||
/^index\.[jt]sx?$/.exec(file)
|
||||
);
|
||||
if (file) {
|
||||
filePath = joinPathFragments(filePath, file);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const fileContent = readFileSync(filePath, 'utf8');
|
||||
|
||||
// use the TypeScript AST to find the path to the file where exportedMember is defined
|
||||
|
||||
@@ -53,6 +53,18 @@
|
||||
"version": "16.0.0-beta.1",
|
||||
"description": "Replace @nrwl/expo with @nx/expo",
|
||||
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
|
||||
},
|
||||
"update-eas-scripts-16-1-4": {
|
||||
"cli": "nx",
|
||||
"version": "16.1.4-beta.0",
|
||||
"description": "Update package.json eas build lifecycle scripts",
|
||||
"implementation": "./src/migrations/update-16-1-4/update-eas-scripts"
|
||||
},
|
||||
"add-detox-app-json-16-1-4": {
|
||||
"version": "16.1.4-beta.0",
|
||||
"cli": "nx",
|
||||
"description": "Add app.json for detox",
|
||||
"factory": "./src/migrations/update-16-1-4/add-detox-app-json"
|
||||
}
|
||||
},
|
||||
"packageJsonUpdates": {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { ExecutorContext, names } from '@nx/devkit';
|
||||
import { join } from 'path';
|
||||
import { join, normalize, sep } from 'path';
|
||||
import { ChildProcess, fork } from 'child_process';
|
||||
|
||||
import { ensureNodeModulesSymlink } from '../../utils/ensure-node-modules-symlink';
|
||||
import { copyBuildFile, unzipBuild } from '../download/download.impl';
|
||||
|
||||
import { ExpoEasBuildOptions } from './schema';
|
||||
import { removeSync } from 'fs-extra';
|
||||
|
||||
export interface ReactNativeBuildOutput {
|
||||
success: boolean;
|
||||
@@ -21,7 +23,20 @@ export default async function* buildExecutor(
|
||||
ensureNodeModulesSymlink(context.root, projectRoot);
|
||||
|
||||
try {
|
||||
// remove the output app if it already existed
|
||||
if (options.local && options.output) {
|
||||
removeSync(options.output);
|
||||
}
|
||||
|
||||
await runCliBuild(context.root, projectRoot, options);
|
||||
|
||||
// unzip the build if it's a tar.gz
|
||||
if (options.local && options.output && options.output.endsWith('.tar.gz')) {
|
||||
const directoryPath = normalize(options.output).split(sep);
|
||||
directoryPath.pop();
|
||||
const outputDirectory = directoryPath.join(sep);
|
||||
await unzipBuild(options.output, outputDirectory);
|
||||
}
|
||||
yield { success: true };
|
||||
} finally {
|
||||
if (childProcess) {
|
||||
@@ -39,7 +54,10 @@ function runCliBuild(
|
||||
childProcess = fork(
|
||||
join(workspaceRoot, './node_modules/eas-cli/bin/run'),
|
||||
['build', ...createBuildOptions(options)],
|
||||
{ cwd: join(workspaceRoot, projectRoot), env: process.env }
|
||||
{
|
||||
cwd: join(workspaceRoot, projectRoot),
|
||||
env: process.env,
|
||||
}
|
||||
);
|
||||
|
||||
// Ensure the child process is killed when the parent exits
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
"description": "Run build locally [experimental]",
|
||||
"default": false
|
||||
},
|
||||
"output": {
|
||||
"type": "string",
|
||||
"description": "Output path for local build"
|
||||
},
|
||||
"wait": {
|
||||
"type": "boolean",
|
||||
"description": "Wait for build(s) to complete",
|
||||
|
||||
@@ -5,7 +5,8 @@ import {
|
||||
createWriteStream,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
} from 'fs';
|
||||
removeSync,
|
||||
} from 'fs-extra';
|
||||
import fetch from 'node-fetch';
|
||||
import { promisify } from 'util';
|
||||
import { pipeline } from 'stream';
|
||||
@@ -56,6 +57,10 @@ export default async function* downloadExecutor(
|
||||
const appName = `${names(build.project?.name).className}${appExtension}`;
|
||||
const outputFilePath = join(options.output, appName);
|
||||
|
||||
if (existsSync(outputFilePath)) {
|
||||
removeSync(outputFilePath);
|
||||
}
|
||||
|
||||
if (downloadFileName.endsWith('.tar.gz')) {
|
||||
await unzipBuild(downloadFilePath, options.output);
|
||||
} else {
|
||||
|
||||
@@ -124,14 +124,14 @@ describe('app', () => {
|
||||
'android.eas': {
|
||||
binaryPath: '../../../apps/my-dir/my-app/dist/MyApp.apk',
|
||||
build:
|
||||
'npx nx run my-app:download --platform android --output=apps/my-dir/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
'npx nx run my-app:download --platform android --output=../../../apps/my-dir/my-app/dist/',
|
||||
type: 'android.apk',
|
||||
},
|
||||
'android.local': {
|
||||
binaryPath: '../../../apps/my-dir/my-app/dist/MyApp.apk',
|
||||
build:
|
||||
'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=apps/my-dir/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=../../../apps/my-dir/my-app/dist/MyApp.apk',
|
||||
type: 'android.apk',
|
||||
},
|
||||
'android.release': {
|
||||
binaryPath:
|
||||
@@ -150,13 +150,13 @@ describe('app', () => {
|
||||
'ios.eas': {
|
||||
binaryPath: '../../../apps/my-dir/my-app/dist/MyApp.app',
|
||||
build:
|
||||
'npx nx run my-app:download --platform ios --distribution simulator --output=apps/my-dir/my-app/dist/',
|
||||
'npx nx run my-app:download --platform ios --distribution simulator --output=../../../apps/my-dir/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
},
|
||||
'ios.local': {
|
||||
binaryPath: '../../../apps/my-dir/my-app/dist/MyApp.app',
|
||||
build:
|
||||
'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=apps/my-dir/my-app/dist/',
|
||||
'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=../../../apps/my-dir/my-app/dist/MyApp.tar.gz',
|
||||
type: 'ios.app',
|
||||
},
|
||||
'ios.release': {
|
||||
@@ -199,14 +199,14 @@ describe('app', () => {
|
||||
'android.eas': {
|
||||
binaryPath: '../../apps/my-app/dist/MyApp.apk',
|
||||
build:
|
||||
'npx nx run my-app:download --platform android --output=apps/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
'npx nx run my-app:download --platform android --output=../../apps/my-app/dist/',
|
||||
type: 'android.apk',
|
||||
},
|
||||
'android.local': {
|
||||
binaryPath: '../../apps/my-app/dist/MyApp.apk',
|
||||
build:
|
||||
'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=apps/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=../../apps/my-app/dist/MyApp.apk',
|
||||
type: 'android.apk',
|
||||
},
|
||||
'android.release': {
|
||||
binaryPath:
|
||||
@@ -225,13 +225,13 @@ describe('app', () => {
|
||||
'ios.eas': {
|
||||
binaryPath: '../../apps/my-app/dist/MyApp.app',
|
||||
build:
|
||||
'npx nx run my-app:download --platform ios --distribution simulator --output=apps/my-app/dist/',
|
||||
'npx nx run my-app:download --platform ios --distribution simulator --output=../../apps/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
},
|
||||
'ios.local': {
|
||||
binaryPath: '../../apps/my-app/dist/MyApp.app',
|
||||
build:
|
||||
'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=apps/my-app/dist/',
|
||||
'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=../../apps/my-app/dist/MyApp.tar.gz',
|
||||
type: 'ios.app',
|
||||
},
|
||||
'ios.release': {
|
||||
@@ -275,14 +275,14 @@ describe('app', () => {
|
||||
'android.eas': {
|
||||
binaryPath: '../../apps/my-app/dist/myappname.apk',
|
||||
build:
|
||||
'npx nx run my-app:download --platform android --output=apps/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
'npx nx run my-app:download --platform android --output=../../apps/my-app/dist/',
|
||||
type: 'android.apk',
|
||||
},
|
||||
'android.local': {
|
||||
binaryPath: '../../apps/my-app/dist/myappname.apk',
|
||||
build:
|
||||
'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=apps/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
'npx nx run my-app:build --platform android --profile preview --wait --local --no-interactive --output=../../apps/my-app/dist/myappname.apk',
|
||||
type: 'android.apk',
|
||||
},
|
||||
'android.release': {
|
||||
binaryPath:
|
||||
@@ -301,13 +301,13 @@ describe('app', () => {
|
||||
'ios.eas': {
|
||||
binaryPath: '../../apps/my-app/dist/myappname.app',
|
||||
build:
|
||||
'npx nx run my-app:download --platform ios --distribution simulator --output=apps/my-app/dist/',
|
||||
'npx nx run my-app:download --platform ios --distribution simulator --output=../../apps/my-app/dist/',
|
||||
type: 'ios.app',
|
||||
},
|
||||
'ios.local': {
|
||||
binaryPath: '../../apps/my-app/dist/myappname.app',
|
||||
build:
|
||||
'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=apps/my-app/dist/',
|
||||
'npx nx run my-app:build --platform ios --profile preview --wait --local --no-interactive --output=../../apps/my-app/dist/myappname.tar.gz',
|
||||
type: 'ios.app',
|
||||
},
|
||||
'ios.release': {
|
||||
|
||||
@@ -7,15 +7,16 @@ import {
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
|
||||
import { runSymlink } from '../../utils/symlink-task';
|
||||
import { addLinting } from '../../utils/add-linting';
|
||||
import { addJest } from '../../utils/add-jest';
|
||||
import { runSymlink } from '../../utils/symlink-task';
|
||||
|
||||
import { normalizeOptions } from './lib/normalize-options';
|
||||
import initGenerator from '../init/init';
|
||||
import { addProject } from './lib/add-project';
|
||||
import { addDetox } from './lib/add-detox';
|
||||
import { createApplicationFiles } from './lib/create-application-files';
|
||||
import { addEasScripts } from './lib/add-eas-scripts';
|
||||
import { addDetox } from './lib/add-detox';
|
||||
import { Schema } from './schema';
|
||||
|
||||
export async function expoApplicationGenerator(
|
||||
@@ -28,23 +29,25 @@ export async function expoApplicationGenerator(
|
||||
addProject(host, options);
|
||||
|
||||
const initTask = await initGenerator(host, { ...options, skipFormat: true });
|
||||
const lintTask = await addLinting(
|
||||
host,
|
||||
options.projectName,
|
||||
options.appProjectRoot,
|
||||
[joinPathFragments(options.appProjectRoot, 'tsconfig.app.json')],
|
||||
options.linter,
|
||||
options.setParserOptionsProject
|
||||
);
|
||||
const lintTask = await addLinting(host, {
|
||||
...options,
|
||||
projectRoot: options.appProjectRoot,
|
||||
tsConfigPaths: [
|
||||
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||
],
|
||||
});
|
||||
|
||||
const jestTask = await addJest(
|
||||
host,
|
||||
options.unitTestRunner,
|
||||
options.projectName,
|
||||
options.appProjectRoot,
|
||||
options.js
|
||||
options.js,
|
||||
options.skipPackageJson
|
||||
);
|
||||
const detoxTask = await addDetox(host, options);
|
||||
const symlinkTask = runSymlink(host.root, options.appProjectRoot);
|
||||
addEasScripts(host);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(host);
|
||||
|
||||
@@ -28,6 +28,15 @@
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png",
|
||||
"bundler": "metro"
|
||||
}
|
||||
},
|
||||
"plugins": [
|
||||
[
|
||||
"@config-plugins/detox",
|
||||
{
|
||||
"skipProguard": false,
|
||||
"subdomains": ["10.0.2.2", "localhost"]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"react-native-web": "*"
|
||||
},
|
||||
"scripts": {
|
||||
<% if (packageManager === 'npm') { %>"eas-build-pre-install": "cd <%= offsetFromRoot %> && cp <%= packageLockFile %> ./<%= appProjectRoot %>/", <% } %>
|
||||
"postinstall": "rm -r node_modules && cd <%= offsetFromRoot %> && <%= packageManager %> install && npx nx sync-deps <%= projectName %> && npx nx ensure-symlink <%= projectName %>"
|
||||
"eas-build-pre-install": "cd <%= offsetFromRoot %> && node tools/scripts/eas-build-pre-install.mjs . <%= appProjectRoot %> && cp <%= packageLockFile %> <%= appProjectRoot %>",
|
||||
"eas-build-post-install": "cd <%= offsetFromRoot %> && node tools/scripts/eas-build-post-install.mjs . <%= appProjectRoot %>"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
|
||||
const preInstallScript = `
|
||||
/*
|
||||
* This script is used to patch the '@nx/expo' package to work with EAS Build.
|
||||
* It is run as the eas-build-pre-install script in the 'package.json' of expo app.
|
||||
* It is executed as 'node tools/scripts/eas-build-pre-install.mjs <workspace root> <project root>'
|
||||
* It will copy the dependencies and devDependencies from the workspace package.json to project's package.json.
|
||||
* This is needed because EAS Build does the install in project's directory and not workspace's directory.
|
||||
*/
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
const [workspaceRoot, projectRoot] = process.argv.slice(2);
|
||||
if (!workspaceRoot) {
|
||||
throw new Error('Missing workspace root');
|
||||
}
|
||||
if (!projectRoot) {
|
||||
throw new Error('Missing project root');
|
||||
}
|
||||
try {
|
||||
const workspacePackage = JSON.parse(
|
||||
readFileSync(join(workspaceRoot, 'package.json')).toString()
|
||||
);
|
||||
const projectPackage = JSON.parse(
|
||||
readFileSync(join(projectRoot, 'package.json')).toString()
|
||||
);
|
||||
projectPackage.dependencies = workspacePackage.dependencies;
|
||||
projectPackage.devDependencies = workspacePackage.devDependencies;
|
||||
writeFileSync(
|
||||
join(projectRoot, 'package.json'),
|
||||
JSON.stringify(projectPackage, null, 2)
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Error reading package.json file', e);
|
||||
}
|
||||
`;
|
||||
|
||||
const postInstallScript = `
|
||||
/**
|
||||
* This script is used to patch the '@nx/expo' package to work with EAS Build.
|
||||
* It is run as a eas-build-post-install script in the 'package.json' of expo app.
|
||||
* It is executed as 'node tools/scripts/eas-build-post-install.mjs <workspace root> <project root>'
|
||||
* It will create a symlink from the project's node_modules to the workspace's node_modules.
|
||||
*/
|
||||
|
||||
import { symlink, existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
const [workspaceRoot, projectRoot] = process.argv.slice(2);
|
||||
|
||||
if (existsSync(join(workspaceRoot, 'node_modules'))) {
|
||||
console.log('Symlink already exists');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
symlink(join(projectRoot, 'node_modules'), join(workspaceRoot, 'node_modules'), 'dir', (err) => {
|
||||
if (err) console.log(err);
|
||||
else {
|
||||
console.log('Symlink created');
|
||||
}
|
||||
});
|
||||
`;
|
||||
|
||||
export function addEasScripts(tree: Tree) {
|
||||
const preInstallScriptPath = 'tools/scripts/eas-build-pre-install.mjs';
|
||||
const postInstallScriptPath = 'tools/scripts/eas-build-post-install.mjs';
|
||||
|
||||
if (!tree.exists(preInstallScriptPath)) {
|
||||
tree.write(preInstallScriptPath, preInstallScript);
|
||||
}
|
||||
if (!tree.exists(postInstallScriptPath)) {
|
||||
tree.write(postInstallScriptPath, postInstallScript);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@
|
||||
"description": "Create an Expo Application for Nx.",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g @nrwl/expo:app myapp --directory=nested",
|
||||
"command": "g @nx/expo:app myapp --directory=nested",
|
||||
"description": "Generate apps/nested/myapp"
|
||||
},
|
||||
{
|
||||
"command": "g @nrwl/expo:app myapp --classComponent",
|
||||
"command": "g @nx/expo:app myapp --classComponent",
|
||||
"description": "Use class components instead of functional components"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g @nrwl/expo:component my-component --project=mylib",
|
||||
"command": "g @nx/expo:component my-component --project=mylib",
|
||||
"description": "Generate a component in the mylib library"
|
||||
},
|
||||
{
|
||||
"command": "g @nrwl/expo:component my-component --project=mylib --classComponent",
|
||||
"command": "g @nx/expo:component my-component --project=mylib --classComponent",
|
||||
"description": "Generate a class component in the mylib library"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "<%= offsetFromRoot %>tsconfig.base.json",
|
||||
"extends": "<%= rootTsConfigPath %>",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-native",
|
||||
"allowJs": true,
|
||||
|
||||
@@ -235,7 +235,7 @@ describe('lib', () => {
|
||||
executor: '@nx/rollup:rollup',
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
external: ['react/jsx-runtime', 'react-native'],
|
||||
external: ['react/jsx-runtime', 'react-native', 'react', 'react-dom'],
|
||||
entryFile: 'libs/my-lib/src/index.ts',
|
||||
outputPath: 'dist/libs/my-lib',
|
||||
project: 'libs/my-lib/package.json',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
addProjectConfiguration,
|
||||
convertNxGenerator,
|
||||
ensurePackage,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
GeneratorCallback,
|
||||
@@ -15,12 +16,11 @@ import {
|
||||
updateJson,
|
||||
} from '@nx/devkit';
|
||||
|
||||
import { addTsConfigPath } from '@nx/js';
|
||||
|
||||
import { addTsConfigPath, getRelativePathToRootTsConfig } from '@nx/js';
|
||||
import init from '../init/init';
|
||||
import { addLinting } from '../../utils/add-linting';
|
||||
import { addJest } from '../../utils/add-jest';
|
||||
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
|
||||
import { Schema } from './schema';
|
||||
|
||||
@@ -35,23 +35,44 @@ export async function expoLibraryGenerator(
|
||||
);
|
||||
}
|
||||
|
||||
addProject(host, options);
|
||||
createFiles(host, options);
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
const initTask = await init(host, {
|
||||
...options,
|
||||
skipFormat: true,
|
||||
e2eTestRunner: 'none',
|
||||
});
|
||||
tasks.push(initTask);
|
||||
|
||||
const lintTask = await addLinting(
|
||||
const addProjectTask = await addProject(host, options);
|
||||
if (addProjectTask) {
|
||||
tasks.push(addProjectTask);
|
||||
}
|
||||
|
||||
createFiles(host, options);
|
||||
|
||||
const lintTask = await addLinting(host, {
|
||||
...options,
|
||||
projectName: options.name,
|
||||
tsConfigPaths: [
|
||||
joinPathFragments(options.projectRoot, 'tsconfig.lib.json'),
|
||||
],
|
||||
});
|
||||
tasks.push(lintTask);
|
||||
|
||||
const jestTask = await addJest(
|
||||
host,
|
||||
options.unitTestRunner,
|
||||
options.name,
|
||||
options.projectRoot,
|
||||
[joinPathFragments(options.projectRoot, 'tsconfig.lib.json')],
|
||||
options.linter,
|
||||
options.setParserOptionsProject
|
||||
options.js,
|
||||
options.skipPackageJson
|
||||
);
|
||||
tasks.push(jestTask);
|
||||
|
||||
if (options.publishable || options.buildable) {
|
||||
updateLibPackageNpmScope(host, options);
|
||||
}
|
||||
|
||||
if (!options.skipTsConfig) {
|
||||
addTsConfigPath(host, options.importPath, [
|
||||
@@ -63,31 +84,30 @@ export async function expoLibraryGenerator(
|
||||
]);
|
||||
}
|
||||
|
||||
const jestTask = await addJest(
|
||||
host,
|
||||
options.unitTestRunner,
|
||||
options.name,
|
||||
options.projectRoot,
|
||||
options.js
|
||||
);
|
||||
|
||||
if (options.publishable || options.buildable) {
|
||||
updateLibPackageNpmScope(host, options);
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(host);
|
||||
}
|
||||
|
||||
return runTasksInSerial(initTask, lintTask, jestTask);
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
function addProject(host: Tree, options: NormalizedSchema) {
|
||||
async function addProject(host: Tree, options: NormalizedSchema) {
|
||||
const targets: { [key: string]: TargetConfiguration } = {};
|
||||
|
||||
let task: GeneratorCallback;
|
||||
if (options.publishable || options.buildable) {
|
||||
const { rollupInitGenerator } = ensurePackage<typeof import('@nx/rollup')>(
|
||||
'@nx/rollup',
|
||||
nxVersion
|
||||
);
|
||||
|
||||
const { libsDir } = getWorkspaceLayout(host);
|
||||
const external = ['react/jsx-runtime', 'react-native'];
|
||||
const external = [
|
||||
'react/jsx-runtime',
|
||||
'react-native',
|
||||
'react',
|
||||
'react-dom',
|
||||
];
|
||||
|
||||
targets.build = {
|
||||
executor: '@nx/rollup:rollup',
|
||||
@@ -108,6 +128,7 @@ function addProject(host: Tree, options: NormalizedSchema) {
|
||||
],
|
||||
},
|
||||
};
|
||||
task = await rollupInitGenerator(host, { ...options, skipFormat: true });
|
||||
}
|
||||
|
||||
addProjectConfiguration(host, options.name, {
|
||||
@@ -117,6 +138,8 @@ function addProject(host: Tree, options: NormalizedSchema) {
|
||||
tags: options.parsedTags,
|
||||
targets,
|
||||
});
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
function updateTsConfig(tree: Tree, options: NormalizedSchema) {
|
||||
@@ -149,6 +172,10 @@ function createFiles(host: Tree, options: NormalizedSchema) {
|
||||
...names(options.name),
|
||||
tmpl: '',
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||
rootTsConfigPath: getRelativePathToRootTsConfig(
|
||||
host,
|
||||
options.projectRoot
|
||||
),
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g @nrwl/expo:lib mylib --directory=myapp",
|
||||
"command": "g @nx/expo:lib mylib --directory=myapp",
|
||||
"description": "Generate libs/myapp/mylib"
|
||||
}
|
||||
],
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user