Compare commits

...

38 Commits

Author SHA1 Message Date
FrozenPandaz 16f0988046 chore(misc): publish 16.1.4 2023-05-09 17:24:47 -04:00
Jason Jean d6afd627f4 fix(devkit): catch errors resolving configs while formatting files (#16872)
(cherry picked from commit ec22b7e540)
2023-05-09 16:19:52 -04:00
Jack Hsu feb2b31d20 fix(nextjs): inline dev-only dependencies and add e2e test to catch issues (#16890)
(cherry picked from commit 854b180013)
2023-05-09 15:10:57 -04:00
Emily Xiong 39f3282535 fix(react-native): fix buildable react native library (#16749)
(cherry picked from commit 8347e61810)
2023-05-09 15:10:54 -04:00
Miroslav Jonaš ad536c4cf9 fix(core): fix version report when version is missing (#16888)
(cherry picked from commit c9a7cd8b01)
2023-05-09 15:10:50 -04:00
Emily Xiong da912b27c9 fix(expo): fix expo detox test (#16779)
(cherry picked from commit 942350810e)
2023-05-09 15:10:45 -04:00
Miroslav Jonaš 5d983ef157 fix(core): keep all explicit dependencies in the graph (#16576)
(cherry picked from commit ae5cdcb86e)
2023-05-09 15:10:39 -04:00
Caleb Ukle 0d90bc8d15 feat(testing): add --strict flag for jest-preset-angular test env opts (#16467)
(cherry picked from commit 50ad516278)
2023-05-09 15:10:35 -04:00
Caleb Ukle f6b05e40c1 fix(js): info about jest global setup/teardown + swc (#16681)
(cherry picked from commit 5743f158ba)
2023-05-09 15:10:28 -04:00
Emily Xiong d1e55b0a05 fix(expo): update package.json eas build scripts to fix eas build (#16742)
(cherry picked from commit ad77b91526)
2023-05-09 15:09:56 -04:00
Caleb Ukle adaee13d46 docs(repo): update docs/schemas to use nx scoped packages - nx labs (#16865)
(cherry picked from commit ad841c9048)
2023-05-09 15:09:39 -04:00
Colum Ferry b439c31b23 fix(angular): handle ngrx imports for apps that do not migrate to config file (#16812)
(cherry picked from commit 6728bbbc98)
2023-05-09 15:09:19 -04:00
Victor Savkin a6642bf2a8 chore(misc): publish 16.1.3 2023-05-08 16:22:12 -04:00
Victor Savkin bd8cbfaddd chore(misc): publish 16.1.3-beta.0 2023-05-08 15:42:19 -04:00
Leosvel Pérez Espinosa 6f03d0c50a feat(angular): update jest-preset-angular to support angular v16 (#16852) 2023-05-08 15:39:35 -04:00
Leosvel Pérez Espinosa 1bbeed0ac0 feat(storybook): update storybook packages to support typescript v5 (#16853) 2023-05-08 15:39:35 -04:00
Jack Hsu c420793d5e fix(nextjs): withNx works with production build (#16867) 2023-05-08 15:39:35 -04:00
Miroslav Jonaš 16c212fc2c fix(linter): support directories for relative path fix (#16854) 2023-05-08 15:39:35 -04:00
FrozenPandaz 4e2d33c9e1 chore(misc): publish 16.1.2 2023-05-08 09:49:49 -04:00
John White 0defcad1a2 fix(core): migrate using yarn when nxJson has another package manager configured (#16844)
(cherry picked from commit 0654776106)
2023-05-08 09:46:22 -04:00
Marwan Fikrat 4233effd06 feat(core): add skipTypeCheck option to rollup plugin options (#16710)
(cherry picked from commit 878df9a618)
2023-05-08 09:46:11 -04:00
FrozenPandaz 1488728aa3 chore(misc): publish 16.1.1 2023-05-05 17:49:50 -04:00
FrozenPandaz a627a0c26f chore(misc): publish 16.1.1-beta.1 2023-05-05 17:45:28 -04:00
FrozenPandaz 75c06380c6 chore(misc): publish 16.1.1-beta.0 2023-05-05 17:45:27 -04:00
FrozenPandaz 127e8d44c1 Revert "chore(misc): publish 16.1.1-beta.0"
This reverts commit fa25a47614.
2023-05-05 17:45:27 -04:00
Jason Jean 6e08e3f7a6 chore(core): add repo information to native packages (#16826) 2023-05-05 17:45:26 -04:00
Jason Jean b93d46dbc9 fix(devkit): fix issue replacing package dependencies in malformed pa… (#16823) 2023-05-05 17:45:26 -04:00
Craigory Coppola 197105af9a fix(misc): make Nx 16 migration safer when treee throws an exception (#16782) 2023-05-05 17:45:25 -04:00
Craigory Coppola 84dd4180ba feat(repo): add CI check for valid codeowners patterns (#16729) 2023-05-05 17:45:24 -04:00
FrozenPandaz f7fcc6facb chore(misc): publish 16.1.1-beta.0 2023-05-05 17:43:58 -04:00
Jack Hsu 8beb4e4424 fix(nextjs): enable Next.js 13.4 support (#16819) 2023-05-05 17:43:57 -04:00
Craigory Coppola 7eec0d73ae fix(core): obey nx.json package manager property (#16777) 2023-05-05 17:43:57 -04:00
Craigory Coppola a0fb8df4d2 fix(devkit): ensure ignore has been initialized in visitNotIgnoredFiles (#16820) 2023-05-05 17:43:56 -04:00
Craigory Coppola 4942eb4965 fix(misc): update URL to point to live page for plugin registry (#16817) 2023-05-05 17:43:56 -04:00
Vinit Neogi f4724bc621 cleanup(misc): add types to getVersion function (#16677) 2023-05-05 17:43:55 -04:00
Jack Hsu 08de51eea7 docs(core): update Next.js version to 13.3.4 (#16818) 2023-05-05 17:43:55 -04:00
James Henry c63bf49c97 chore(core): enable provenance and update lerna usage (#16814) 2023-05-05 17:43:54 -04:00
Leosvel Pérez Espinosa e7e78c56cd fix(core): handle schema property with const value (#16797) 2023-05-05 17:43:54 -04:00
167 changed files with 2498 additions and 1843 deletions
+1 -1
View File
@@ -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 &
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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`"
}
],
+9 -33
View File
@@ -1,7 +1,5 @@
# React Native with Nx
![React Logo](/shared/react-logo.png)
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
+38 -5
View File
@@ -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
+6
View File
@@ -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 |
+1 -1
View File
@@ -232,7 +232,7 @@ describe('Linter', () => {
import '@${projScope}/${invalidtaglib}';
import '@${projScope}/${validtaglib}';
const s = {loadChildren: '@${projScope}/${lazylib}'};
const s = {loadChildren: '@secondScope/${lazylib}'};
`
);
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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"
]
+16
View File
@@ -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."
}
],
+1 -1
View File
@@ -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"
}
],
+19
View File
@@ -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
}
}
}
}
}
+1 -1
View File
@@ -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: {
+6 -2
View File
@@ -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
View File
@@ -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);
}
+2 -1
View File
@@ -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
+21 -21
View File
@@ -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');
+36 -21
View File
@@ -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)
);
});
}
+11 -1
View File
@@ -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
+12
View File
@@ -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',
+51 -24
View File
@@ -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