feat(misc): v19 cleanup for Nx plugins (#23104)
This PR removes deprecated code that's been slated for removal in Nx 19 - mentioned as `TODO(v19)` comments. ## Breaking Changes - **CNW:** `create-nx-workspace` no longer support `--preset=empty` and `--preset=core`, use `--preset=apps` and `--preset=npm` respectively. Deprecated in Nx 15.9. - **Next.js:** `NX_` environment variables are no longer bundled into Next.js apps, use `NEXT_PUBLIC` instead. Deprecated in Nx 16.8. - **Webpack, Storybook, Esbuild:** `NX_` environment variables are no longer bundled into browser bundles, use `NX_PUBLIC` instead. This removes the possibility of intentional bundling of `NX_` variables. Deprecated in Nx 18. - **Cypress:** `cypressComponentConfiguration` generator removed from `@nx/cypress`, use `configurationGenerator`instead. Deprecated in Nx 16.8. - **Cypress:** `cypressProjectGenerator` generator removed from `@nx/cypress`, use `configurationGenerator` instead. Deprecated in Nx 15.9. - **Expo:** `withNxWebpack` removed from `@nx/expo`, use [metro bundler](https://docs.expo.dev/guides/customizing-metro/) (https://docs.expo.dev/guides/customizing-metro/) in app.json instead. There is a migration to handle this in Nx 19. Deprecated in Nx 15.8. ## Deferred to v20 - **JS:** `classProperties.loose` option removed from `@nx/js/babel` preset, use `loose` instead. Deprecated in Nx 17.0. - **ESLint:** Low priority task to "deviations from @typescript-eslint/recommended" for our lint rules. @JamesHenry will look at this later before Nx 20, but it is unimportant. - **React:** component testing does not work with Project Crystal, and we need the executor + built-in webpack configs to run CT. Will do a follow-up on this after Nx 19 release. Related issue: https://github.com/nrwl/nx/issues/21546 - **Next.js:** `withStylus` removal from `@nx/next`, use SASS instead. It hasn't worked, but we kept the file to throw an error when used. Deprecated in Nx 17.0. - **Next.js**: `@nx/next:component` and `@nx/next:page` generators to not derive the `components` and `app`/`pages` directory. Use `nx g @nx/next:component apps/myapp/components/button` instead. Deprecated in Nx 17.0. - **Webpack:** `isolatedConfig` option removal from `@nx/webpack:webpack` executor. There is a migration to handle this in Nx 19. Deprecated in in Nx 17.2. - **Angular:** `executeWebpackDevServerBuilder` removal from `@nx/angular/executors`, use `executeDevServerBuilder` instead. Deprecated in Nx 17.0.
This commit is contained in:
parent
35f0618347
commit
2e621f324c
@ -145,7 +145,7 @@ Prefix to use for Angular component and directive selectors.
|
|||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|
||||||
Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "nuxt", "nuxt-standalone", "next", "nextjs-standalone", "remix-monorepo", "remix-standalone", "react-native", "expo", "nest", "express", "react", "vue", "angular", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset
|
Customizes the initial content of your workspace. Default presets include: ["apps", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "nuxt", "nuxt-standalone", "next", "nextjs-standalone", "remix-monorepo", "remix-standalone", "react-native", "expo", "nest", "express", "react", "vue", "angular", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset
|
||||||
|
|
||||||
### routing
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -7017,14 +7017,6 @@
|
|||||||
"isExternal": false,
|
"isExternal": false,
|
||||||
"disableCollapsible": false
|
"disableCollapsible": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "cypress-project",
|
|
||||||
"path": "/nx-api/cypress/generators/cypress-project",
|
|
||||||
"name": "cypress-project",
|
|
||||||
"children": [],
|
|
||||||
"isExternal": false,
|
|
||||||
"disableCollapsible": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "configuration",
|
"id": "configuration",
|
||||||
"path": "/nx-api/cypress/generators/configuration",
|
"path": "/nx-api/cypress/generators/configuration",
|
||||||
|
|||||||
@ -510,15 +510,6 @@
|
|||||||
"path": "/nx-api/cypress/generators/init",
|
"path": "/nx-api/cypress/generators/init",
|
||||||
"type": "generator"
|
"type": "generator"
|
||||||
},
|
},
|
||||||
"/nx-api/cypress/generators/cypress-project": {
|
|
||||||
"description": "Add a Cypress E2E Project.",
|
|
||||||
"file": "generated/packages/cypress/generators/cypress-project.json",
|
|
||||||
"hidden": true,
|
|
||||||
"name": "cypress-project",
|
|
||||||
"originalFilePath": "/packages/cypress/src/generators/cypress-project/schema.json",
|
|
||||||
"path": "/nx-api/cypress/generators/cypress-project",
|
|
||||||
"type": "generator"
|
|
||||||
},
|
|
||||||
"/nx-api/cypress/generators/configuration": {
|
"/nx-api/cypress/generators/configuration": {
|
||||||
"description": "Add a Cypress E2E Configuration to an existing project.",
|
"description": "Add a Cypress E2E Configuration to an existing project.",
|
||||||
"file": "generated/packages/cypress/generators/configuration.json",
|
"file": "generated/packages/cypress/generators/configuration.json",
|
||||||
|
|||||||
@ -502,15 +502,6 @@
|
|||||||
"path": "cypress/generators/init",
|
"path": "cypress/generators/init",
|
||||||
"type": "generator"
|
"type": "generator"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"description": "Add a Cypress E2E Project.",
|
|
||||||
"file": "generated/packages/cypress/generators/cypress-project.json",
|
|
||||||
"hidden": true,
|
|
||||||
"name": "cypress-project",
|
|
||||||
"originalFilePath": "/packages/cypress/src/generators/cypress-project/schema.json",
|
|
||||||
"path": "cypress/generators/cypress-project",
|
|
||||||
"type": "generator"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Add a Cypress E2E Configuration to an existing project.",
|
"description": "Add a Cypress E2E Configuration to an existing project.",
|
||||||
"file": "generated/packages/cypress/generators/configuration.json",
|
"file": "generated/packages/cypress/generators/configuration.json",
|
||||||
|
|||||||
@ -1,84 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "cypress-project",
|
|
||||||
"factory": "./src/generators/cypress-project/cypress-project#cypressProjectGeneratorInternal",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/schema",
|
|
||||||
"$id": "NxCypressProjectGeneratorSchema",
|
|
||||||
"cli": "nx",
|
|
||||||
"title": "Create Cypress Configuration for the workspace",
|
|
||||||
"description": "Create Cypress Configuration for the workspace.",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"project": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The name of the frontend project to test.",
|
|
||||||
"$default": { "$source": "projectName" },
|
|
||||||
"x-priority": "important"
|
|
||||||
},
|
|
||||||
"baseUrl": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The address (with the port) which your application is running on."
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Name of the E2E Project.",
|
|
||||||
"$default": { "$source": "argv", "index": 0 },
|
|
||||||
"x-prompt": "What name would you like to use for the e2e project?"
|
|
||||||
},
|
|
||||||
"directory": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A directory where the project is placed.",
|
|
||||||
"x-priority": "important"
|
|
||||||
},
|
|
||||||
"projectNameAndRootFormat": {
|
|
||||||
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["as-provided", "derived"]
|
|
||||||
},
|
|
||||||
"linter": {
|
|
||||||
"description": "The tool to use for running lint checks.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["eslint", "none"],
|
|
||||||
"default": "eslint"
|
|
||||||
},
|
|
||||||
"js": {
|
|
||||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
|
||||||
"description": "Skip formatting files.",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"x-priority": "internal"
|
|
||||||
},
|
|
||||||
"setParserOptionsProject": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"skipPackageJson": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
|
||||||
"x-priority": "internal"
|
|
||||||
},
|
|
||||||
"bundler": {
|
|
||||||
"description": "The Cypress bundler to use.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["vite", "webpack", "none"],
|
|
||||||
"x-prompt": "Which Cypress bundler do you want to use?",
|
|
||||||
"default": "webpack"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["name"],
|
|
||||||
"examplesFile": "Adding Cypress to an existing application requires two options. The name of the e2e app to create and what project that e2e app is for.\n\n```bash\nnx g configuration --name=my-app-e2e --project=my-app\n```\n\nWhen providing `--project` option, the generator will look for the `serve` target in that given project. This allows the [cypress executor](/packages/cypress/executors/cypress) to spin up the project and start the cypress runner.\n\nIf you prefer to not have the project served automatically, you can provide a `--base-url` argument in place of `--project`\n\n```bash\nnx g configuration --name=my-app-e2e --base-url=http://localhost:1234\n```\n\n{% callout type=\"note\" title=\"What about API Projects?\" %}\nYou can also run the `configuration` generator against API projects like a [Nest API](/packages/nest/generators/application#@nx/nest:application).\nIf there is a URL to visit then you can test it with Cypress!\n{% /callout %}\n\n## Using Cypress with Vite.js\n\nNow, you can generate your Cypress project with Vite.js as the bundler:\n\n```bash\nnx g configuration --name=my-app-e2e --project=my-app --bundler=vite\n```\n\nThis generator will pass the `bundler` information (`bundler: 'vite'`) to our `nxE2EPreset`, in your project's `cypress.config.ts` file (eg. `my-app-e2e/cypress.config.ts`).\n\n### Customizing the Vite.js configuration\n\nThe `nxE2EPreset` will then use the `bundler` information to generate the correct settings for your Cypress project to use Vite.js. In the background, the way this works is that it's using a custom Vite preprocessor for your files, that's called on the `file:preprocessor` event. If you want to customize this behaviour, you can do so like this in your project's `cypress.config.ts` file:\n\n```ts\nimport { defineConfig } from 'cypress';\nimport { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';\n\nconst config = nxE2EPreset(__filename, { bundler: 'vite' });\nexport default defineConfig({\n e2e: {\n ...config,\n async setupNodeEvents(on, config) {\n // Ensure that `@nx/cypress` events are set up.\n await config.setupNodeEvents(on, config);\n\n // Your settings here\n },\n },\n});\n```\n",
|
|
||||||
"presets": []
|
|
||||||
},
|
|
||||||
"description": "Add a Cypress E2E Project.",
|
|
||||||
"hidden": true,
|
|
||||||
"implementation": "/packages/cypress/src/generators/cypress-project/cypress-project#cypressProjectGeneratorInternal.ts",
|
|
||||||
"aliases": [],
|
|
||||||
"path": "/packages/cypress/src/generators/cypress-project/schema.json",
|
|
||||||
"type": "generator"
|
|
||||||
}
|
|
||||||
@ -145,7 +145,7 @@ Prefix to use for Angular component and directive selectors.
|
|||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|
||||||
Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "nuxt", "nuxt-standalone", "next", "nextjs-standalone", "remix-monorepo", "remix-standalone", "react-native", "expo", "nest", "express", "react", "vue", "angular", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset
|
Customizes the initial content of your workspace. Default presets include: ["apps", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "nuxt", "nuxt-standalone", "next", "nextjs-standalone", "remix-monorepo", "remix-standalone", "react-native", "expo", "nest", "express", "react", "vue", "angular", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset
|
||||||
|
|
||||||
### routing
|
### routing
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -368,7 +368,6 @@
|
|||||||
- [cypress](/nx-api/cypress/executors/cypress)
|
- [cypress](/nx-api/cypress/executors/cypress)
|
||||||
- [generators](/nx-api/cypress/generators)
|
- [generators](/nx-api/cypress/generators)
|
||||||
- [init](/nx-api/cypress/generators/init)
|
- [init](/nx-api/cypress/generators/init)
|
||||||
- [cypress-project](/nx-api/cypress/generators/cypress-project)
|
|
||||||
- [configuration](/nx-api/cypress/generators/configuration)
|
- [configuration](/nx-api/cypress/generators/configuration)
|
||||||
- [component-configuration](/nx-api/cypress/generators/component-configuration)
|
- [component-configuration](/nx-api/cypress/generators/component-configuration)
|
||||||
- [migrate-to-cypress-11](/nx-api/cypress/generators/migrate-to-cypress-11)
|
- [migrate-to-cypress-11](/nx-api/cypress/generators/migrate-to-cypress-11)
|
||||||
|
|||||||
@ -154,10 +154,10 @@ export default defineConfig({
|
|||||||
async () => {
|
async () => {
|
||||||
const appName = uniq('next-cy-app');
|
const appName = uniq('next-cy-app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${appName} --e2eTestRunner=none --no-interactive`
|
`generate @nx/next:app ${appName} --directory=apps/${appName} --e2eTestRunner=none --no-interactive --projectNameAndRootFormat=as-provided`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:component btn --project=${appName} --no-interactive`
|
`generate @nx/next:component btn --project=${appName} --directory=apps/${appName}/components --nameAndDirectoryFormat=as-provided --no-interactive`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:cypress-component-configuration --project=${appName} --generate-tests --no-interactive`
|
`generate @nx/next:cypress-component-configuration --project=${appName} --generate-tests --no-interactive`
|
||||||
|
|||||||
@ -118,10 +118,10 @@ function addBabelSupport(path: string) {
|
|||||||
|
|
||||||
function createAppWithCt(appName: string) {
|
function createAppWithCt(appName: string) {
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:app ${appName} --no-interactive --appDir=false --src=false`
|
`generate @nx/next:app ${appName} --directory=apps/${appName} --no-interactive --appDir=false --src=false --projectNameAndRootFormat=as-provided`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/next:component button --project=${appName} --directory=components --flat --no-interactive`
|
`generate @nx/next:component button --project=${appName} --directory=apps/${appName}/components --nameAndDirectoryFormat=as-provided --no-interactive`
|
||||||
);
|
);
|
||||||
createFile(
|
createFile(
|
||||||
`apps/${appName}/public/data.json`,
|
`apps/${appName}/public/data.json`,
|
||||||
|
|||||||
@ -244,7 +244,7 @@ describe('index.html interpolation (legacy)', () => {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='root'></div>
|
<div id='root'></div>
|
||||||
<div>Nx Variable: %NX_VARIABLE%</div>
|
<div>Nx Variable: %NX_PUBLIC_VARIABLE%</div>
|
||||||
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
||||||
<div>Deploy Url: %DEPLOY_URL%</div>
|
<div>Deploy Url: %DEPLOY_URL%</div>
|
||||||
</body>
|
</body>
|
||||||
@ -252,7 +252,7 @@ describe('index.html interpolation (legacy)', () => {
|
|||||||
`;
|
`;
|
||||||
const envFilePath = `apps/${appName}/.env`;
|
const envFilePath = `apps/${appName}/.env`;
|
||||||
const envFileContents = `
|
const envFileContents = `
|
||||||
NX_VARIABLE=foo
|
NX_PUBLIC_VARIABLE=foo
|
||||||
SOME_OTHER_VARIABLE=bar
|
SOME_OTHER_VARIABLE=bar
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
|||||||
@ -243,39 +243,39 @@ describe('CLI - Environment Variables', () => {
|
|||||||
//test if the Nx CLI loads root .env vars
|
//test if the Nx CLI loads root .env vars
|
||||||
updateFile(
|
updateFile(
|
||||||
`.env`,
|
`.env`,
|
||||||
'NX_WS_BASE=ws-base\nNX_SHARED_ENV=shared-in-workspace-base'
|
'NX_PUBLIC_WS_BASE=ws-base\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-base'
|
||||||
);
|
);
|
||||||
updateFile(
|
updateFile(
|
||||||
`.env.local`,
|
`.env.local`,
|
||||||
'NX_WS_ENV_LOCAL=ws-env-local\nNX_SHARED_ENV=shared-in-workspace-env-local'
|
'NX_PUBLIC_WS_ENV_LOCAL=ws-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-env-local'
|
||||||
);
|
);
|
||||||
updateFile(
|
updateFile(
|
||||||
`.local.env`,
|
`.local.env`,
|
||||||
'NX_WS_LOCAL_ENV=ws-local-env\nNX_SHARED_ENV=shared-in-workspace-local-env'
|
'NX_PUBLIC_WS_LOCAL_ENV=ws-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-local-env'
|
||||||
);
|
);
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${appName}/.env`,
|
`apps/${appName}/.env`,
|
||||||
'NX_APP_BASE=app-base\nNX_SHARED_ENV=shared-in-app-base'
|
'NX_PUBLIC_APP_BASE=app-base\nNX_PUBLIC_SHARED_ENV=shared-in-app-base'
|
||||||
);
|
);
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${appName}/.env.local`,
|
`apps/${appName}/.env.local`,
|
||||||
'NX_APP_ENV_LOCAL=app-env-local\nNX_SHARED_ENV=shared-in-app-env-local'
|
'NX_PUBLIC_APP_ENV_LOCAL=app-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-app-env-local'
|
||||||
);
|
);
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${appName}/.local.env`,
|
`apps/${appName}/.local.env`,
|
||||||
'NX_APP_LOCAL_ENV=app-local-env\nNX_SHARED_ENV=shared-in-app-local-env'
|
'NX_PUBLIC_APP_LOCAL_ENV=app-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-app-local-env'
|
||||||
);
|
);
|
||||||
const main = `apps/${appName}/src/main.ts`;
|
const main = `apps/${appName}/src/main.ts`;
|
||||||
const newCode = `
|
const newCode = `
|
||||||
const envVars = [process.env.NODE_ENV, process.env.NX_WS_BASE, process.env.NX_WS_ENV_LOCAL, process.env.NX_WS_LOCAL_ENV, process.env.NX_APP_BASE, process.env.NX_APP_ENV_LOCAL, process.env.NX_APP_LOCAL_ENV, process.env.NX_SHARED_ENV];
|
const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];
|
||||||
const nodeEnv = process.env.NODE_ENV;
|
const nodeEnv = process.env.NODE_ENV;
|
||||||
const nxWsBase = process.env.NX_WS_BASE;
|
const nxWsBase = process.env.NX_PUBLIC_WS_BASE;
|
||||||
const nxWsEnvLocal = process.env.NX_WS_ENV_LOCAL;
|
const nxWsEnvLocal = process.env.NX_PUBLIC_WS_ENV_LOCAL;
|
||||||
const nxWsLocalEnv = process.env.NX_WS_LOCAL_ENV;
|
const nxWsLocalEnv = process.env.NX_PUBLIC_WS_LOCAL_ENV;
|
||||||
const nxAppBase = process.env.NX_APP_BASE;
|
const nxAppBase = process.env.NX_PUBLIC_APP_BASE;
|
||||||
const nxAppEnvLocal = process.env.NX_APP_ENV_LOCAL;
|
const nxAppEnvLocal = process.env.NX_PUBLIC_APP_ENV_LOCAL;
|
||||||
const nxAppLocalEnv = process.env.NX_APP_LOCAL_ENV;
|
const nxAppLocalEnv = process.env.NX_PUBLIC_APP_LOCAL_ENV;
|
||||||
const nxSharedEnv = process.env.NX_SHARED_ENV;
|
const nxSharedEnv = process.env.NX_PUBLIC_SHARED_ENV;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
@ -290,18 +290,18 @@ describe('CLI - Environment Variables', () => {
|
|||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${appName2}/.env`,
|
`apps/${appName2}/.env`,
|
||||||
'NX_APP_BASE=app2-base\nNX_SHARED_ENV=shared2-in-app-base'
|
'NX_PUBLIC_APP_BASE=app2-base\nNX_PUBLIC_SHARED_ENV=shared2-in-app-base'
|
||||||
);
|
);
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${appName2}/.env.local`,
|
`apps/${appName2}/.env.local`,
|
||||||
'NX_APP_ENV_LOCAL=app2-env-local\nNX_SHARED_ENV=shared2-in-app-env-local'
|
'NX_PUBLIC_APP_ENV_LOCAL=app2-env-local\nNX_PUBLIC_SHARED_ENV=shared2-in-app-env-local'
|
||||||
);
|
);
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${appName2}/.local.env`,
|
`apps/${appName2}/.local.env`,
|
||||||
'NX_APP_LOCAL_ENV=app2-local-env\nNX_SHARED_ENV=shared2-in-app-local-env'
|
'NX_PUBLIC_APP_LOCAL_ENV=app2-local-env\nNX_PUBLIC_SHARED_ENV=shared2-in-app-local-env'
|
||||||
);
|
);
|
||||||
const main2 = `apps/${appName2}/src/main.ts`;
|
const main2 = `apps/${appName2}/src/main.ts`;
|
||||||
const newCode2 = `const envVars = [process.env.NODE_ENV, process.env.NX_WS_BASE, process.env.NX_WS_ENV_LOCAL, process.env.NX_WS_LOCAL_ENV, process.env.NX_APP_BASE, process.env.NX_APP_ENV_LOCAL, process.env.NX_APP_LOCAL_ENV, process.env.NX_SHARED_ENV];`;
|
const newCode2 = `const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];`;
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app ${appName2} --bundler=webpack --no-interactive --compiler=babel`
|
`generate @nx/web:app ${appName2} --bundler=webpack --no-interactive --compiler=babel`
|
||||||
@ -361,14 +361,14 @@ describe('index.html interpolation', () => {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='root'></div>
|
<div id='root'></div>
|
||||||
<div>Nx Variable: %NX_VARIABLE%</div>
|
<div>Nx Variable: %NX_PUBLIC_VARIABLE%</div>
|
||||||
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`;
|
`;
|
||||||
const envFilePath = `apps/${appName}/.env`;
|
const envFilePath = `apps/${appName}/.env`;
|
||||||
const envFileContents = `
|
const envFileContents = `
|
||||||
NX_VARIABLE=foo
|
NX_PUBLIC_VARIABLE=foo
|
||||||
SOME_OTHER_VARIABLE=bar
|
SOME_OTHER_VARIABLE=bar
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
|||||||
@ -164,22 +164,18 @@ describe('Webpack Plugin', () => {
|
|||||||
expect(output).toMatch(/Hello/);
|
expect(output).toMatch(/Hello/);
|
||||||
}, 500_000);
|
}, 500_000);
|
||||||
|
|
||||||
it('should bundle in non-sensitive NX_ environment variables', () => {
|
it('should bundle in NX_PUBLIC_ environment variables', () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(`generate @nx/web:app ${appName} --bundler webpack`);
|
runCLI(`generate @nx/web:app ${appName} --bundler webpack`);
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${appName}/src/main.ts`,
|
`apps/${appName}/src/main.ts`,
|
||||||
`
|
`
|
||||||
console.log(process.env['NX_CLOUD_ENCRYPTION_KEY']);
|
|
||||||
console.log(process.env['NX_CLOUD_ACCESS_TOKEN']);
|
|
||||||
console.log(process.env['NX_PUBLIC_TEST']);
|
console.log(process.env['NX_PUBLIC_TEST']);
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`build ${appName}`, {
|
runCLI(`build ${appName}`, {
|
||||||
env: {
|
env: {
|
||||||
NX_CLOUD_ENCRYPTION_KEY: 'secret',
|
|
||||||
NX_CLOUD_ACCESS_TOKEN: 'secret',
|
|
||||||
NX_PUBLIC_TEST: 'foobar',
|
NX_PUBLIC_TEST: 'foobar',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -188,7 +184,6 @@ describe('Webpack Plugin', () => {
|
|||||||
f.startsWith('main.')
|
f.startsWith('main.')
|
||||||
);
|
);
|
||||||
const content = readFile(`dist/apps/${appName}/${mainFile}`);
|
const content = readFile(`dist/apps/${appName}/${mainFile}`);
|
||||||
expect(content).not.toMatch(/secret/);
|
|
||||||
expect(content).toMatch(/foobar/);
|
expect(content).toMatch(/foobar/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -95,10 +95,6 @@ const pages: Array<{ title: string; path: string }> = [
|
|||||||
},
|
},
|
||||||
{ title: '@nx/cypress', path: '/packages/cypress' },
|
{ title: '@nx/cypress', path: '/packages/cypress' },
|
||||||
{ title: '@nx/cypress:init', path: '/packages/cypress/generators/init' },
|
{ title: '@nx/cypress:init', path: '/packages/cypress/generators/init' },
|
||||||
{
|
|
||||||
title: '@nx/cypress:cypress-project',
|
|
||||||
path: '/packages/cypress/generators/cypress-project',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '@nx/cypress:cypress',
|
title: '@nx/cypress:cypress',
|
||||||
path: '/packages/cypress/executors/cypress',
|
path: '/packages/cypress/executors/cypress',
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export * from '@nx/expo/plugins/with-nx-webpack';
|
|
||||||
@ -12,9 +12,9 @@ export * from './src/executors/extract-i18n/extract-i18n.impl';
|
|||||||
import { executeDevServerBuilder } from './src/builders/dev-server/dev-server.impl';
|
import { executeDevServerBuilder } from './src/builders/dev-server/dev-server.impl';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
// TODO(v19): remove this alias
|
// TODO(v20): remove this alias
|
||||||
/**
|
/**
|
||||||
* @deprecated Use executeDevServerBuilder instead. It will be removed in Nx v19.
|
* @deprecated Use executeDevServerBuilder instead. It will be removed in Nx v20.
|
||||||
*/
|
*/
|
||||||
executeDevServerBuilder as executeWebpackDevServerBuilder,
|
executeDevServerBuilder as executeWebpackDevServerBuilder,
|
||||||
executeDevServerBuilder,
|
executeDevServerBuilder,
|
||||||
|
|||||||
@ -196,14 +196,7 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
|
|||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[
|
[normalizeArgsMiddleware] as yargs.MiddlewareFunction<{}>[]
|
||||||
normalizeArgsMiddleware,
|
|
||||||
normalizeAndWarnOnDeprecatedPreset({
|
|
||||||
// TODO(v19): Remove Empty and Core presets
|
|
||||||
[Preset.Core]: Preset.NPM,
|
|
||||||
[Preset.Empty]: Preset.Apps,
|
|
||||||
}),
|
|
||||||
] as yargs.MiddlewareFunction<{}>[]
|
|
||||||
)
|
)
|
||||||
.help('help', chalk.dim`Show help`)
|
.help('help', chalk.dim`Show help`)
|
||||||
.updateLocale(yargsDecorator)
|
.updateLocale(yargsDecorator)
|
||||||
@ -248,28 +241,6 @@ async function main(parsedArgs: yargs.Arguments<Arguments>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeAndWarnOnDeprecatedPreset(
|
|
||||||
deprecatedPresets: Partial<Record<Preset, Preset>>
|
|
||||||
): (argv: yargs.Arguments<Arguments>) => Promise<void> {
|
|
||||||
return async (args: yargs.Arguments<Arguments>): Promise<void> => {
|
|
||||||
if (!args.preset) return;
|
|
||||||
if (deprecatedPresets[args.preset]) {
|
|
||||||
output.addVerticalSeparator();
|
|
||||||
output.note({
|
|
||||||
title: `The "${args.preset}" preset is deprecated.`,
|
|
||||||
bodyLines: [
|
|
||||||
`The "${
|
|
||||||
args.preset
|
|
||||||
}" preset will be removed in a future Nx release. Use the "${
|
|
||||||
deprecatedPresets[args.preset]
|
|
||||||
}" preset instead.`,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
args.preset = deprecatedPresets[args.preset] as Preset;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is used to normalize the arguments passed to the command.
|
* This function is used to normalize the arguments passed to the command.
|
||||||
* It would:
|
* It would:
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
export enum Preset {
|
export enum Preset {
|
||||||
Apps = 'apps',
|
Apps = 'apps',
|
||||||
Empty = 'empty', // same as apps, deprecated
|
|
||||||
Core = 'core', // same as npm, deprecated
|
|
||||||
NPM = 'npm',
|
NPM = 'npm',
|
||||||
TS = 'ts',
|
TS = 'ts',
|
||||||
WebComponents = 'web-components',
|
WebComponents = 'web-components',
|
||||||
|
|||||||
@ -9,12 +9,6 @@
|
|||||||
"aliases": ["ng-add"],
|
"aliases": ["ng-add"],
|
||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
"cypress-project": {
|
|
||||||
"factory": "./src/generators/cypress-project/cypress-project#cypressProjectGeneratorInternal",
|
|
||||||
"schema": "./src/generators/cypress-project/schema.json",
|
|
||||||
"description": "Add a Cypress E2E Project.",
|
|
||||||
"hidden": true
|
|
||||||
},
|
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"aliases": ["cypress-e2e-configuration", "e2e", "e2e-config"],
|
"aliases": ["cypress-e2e-configuration", "e2e", "e2e-config"],
|
||||||
"factory": "./src/generators/configuration/configuration#configurationGeneratorInternal",
|
"factory": "./src/generators/configuration/configuration#configurationGeneratorInternal",
|
||||||
|
|||||||
@ -1,17 +1,4 @@
|
|||||||
import { configurationGenerator } from './src/generators/configuration/configuration';
|
export { configurationGenerator } from './src/generators/configuration/configuration';
|
||||||
import { componentConfigurationGenerator } from './src/generators/component-configuration/component-configuration';
|
export { componentConfigurationGenerator } from './src/generators/component-configuration/component-configuration';
|
||||||
import { cypressProjectGenerator as _cypressProjectGenerator } from './src/generators/cypress-project/cypress-project';
|
|
||||||
|
|
||||||
export { configurationGenerator, componentConfigurationGenerator };
|
|
||||||
|
|
||||||
// Maintain backwards compatibility with the old names in case community plugins used them.
|
|
||||||
// TODO(v19): Remove old name
|
|
||||||
/** @deprecated Use `configurationGenerator` instead. It will be removed in Nx 19. */
|
|
||||||
export const cypressComponentConfiguration = componentConfigurationGenerator;
|
|
||||||
|
|
||||||
export { configurationGenerator as cypressE2EConfigurationGenerator };
|
|
||||||
// TODO(v19): Remove project generator
|
|
||||||
/** @deprecated Add a new project and call `configurationGenerator` instead. It will be removed in Nx 19. */
|
|
||||||
export const cypressProjectGenerator = _cypressProjectGenerator;
|
|
||||||
export { cypressInitGenerator } from './src/generators/init/init';
|
export { cypressInitGenerator } from './src/generators/init/init';
|
||||||
export { migrateCypressProject } from './src/generators/migrate-to-cypress-11/migrate-to-cypress-11';
|
export { migrateCypressProject } from './src/generators/migrate-to-cypress-11/migrate-to-cypress-11';
|
||||||
|
|||||||
@ -39,7 +39,6 @@
|
|||||||
"@nx/js": "file:../js",
|
"@nx/js": "file:../js",
|
||||||
"@phenomnomnominal/tsquery": "~5.0.1",
|
"@phenomnomnominal/tsquery": "~5.0.1",
|
||||||
"detect-port": "^1.5.1",
|
"detect-port": "^1.5.1",
|
||||||
"semver": "^7.5.3",
|
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@ -1,240 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`Cypress Project < v7 --linter eslint should add eslint-plugin-cypress 1`] = `
|
|
||||||
{
|
|
||||||
"extends": [
|
|
||||||
"plugin:cypress/recommended",
|
|
||||||
"../.eslintrc.json",
|
|
||||||
],
|
|
||||||
"ignorePatterns": [
|
|
||||||
"!**/*",
|
|
||||||
],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"*.ts",
|
|
||||||
"*.tsx",
|
|
||||||
"*.js",
|
|
||||||
"*.jsx",
|
|
||||||
],
|
|
||||||
"rules": {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
"src/plugins/index.js",
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/no-var-requires": "off",
|
|
||||||
"no-undef": "off",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project < v7 nested should update configuration 1`] = `
|
|
||||||
{
|
|
||||||
"e2e": {
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"devServerTarget": "my-dir-my-app:serve:production",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"executor": "@nx/cypress:cypress",
|
|
||||||
"options": {
|
|
||||||
"cypressConfig": "my-dir/my-app-e2e/cypress.json",
|
|
||||||
"devServerTarget": "my-dir-my-app:serve",
|
|
||||||
"testingType": "e2e",
|
|
||||||
"tsConfig": "my-dir/my-app-e2e/tsconfig.json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nx/eslint:lint",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project < v7 project with directory in its name should set right path names in \`cypress.json\` 1`] = `
|
|
||||||
"{
|
|
||||||
"fileServerFolder": ".",
|
|
||||||
"fixturesFolder": "./src/fixtures",
|
|
||||||
"integrationFolder": "./src/integration",
|
|
||||||
"modifyObstructiveCode": false,
|
|
||||||
"supportFile": "./src/support/index.ts",
|
|
||||||
"pluginsFile": "./src/plugins/index",
|
|
||||||
"video": true,
|
|
||||||
"videosFolder": "../../dist/cypress/my-dir/my-app-e2e/videos",
|
|
||||||
"screenshotsFolder": "../../dist/cypress/my-dir/my-app-e2e/screenshots",
|
|
||||||
"chromeWebSecurity": false
|
|
||||||
}
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project < v7 project with directory in its name should update configuration 1`] = `
|
|
||||||
{
|
|
||||||
"e2e": {
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"devServerTarget": "my-dir-my-app:serve:production",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"executor": "@nx/cypress:cypress",
|
|
||||||
"options": {
|
|
||||||
"cypressConfig": "my-dir/my-app-e2e/cypress.json",
|
|
||||||
"devServerTarget": "my-dir-my-app:serve",
|
|
||||||
"testingType": "e2e",
|
|
||||||
"tsConfig": "my-dir/my-app-e2e/tsconfig.json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nx/eslint:lint",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project < v7 should update project configuration (baseUrl) 1`] = `
|
|
||||||
{
|
|
||||||
"e2e": {
|
|
||||||
"executor": "@nx/cypress:cypress",
|
|
||||||
"options": {
|
|
||||||
"baseUrl": "http://localhost:3000",
|
|
||||||
"cypressConfig": "my-app-e2e/cypress.json",
|
|
||||||
"testingType": "e2e",
|
|
||||||
"tsConfig": "my-app-e2e/tsconfig.json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nx/eslint:lint",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project < v7 should update project configuration 1`] = `
|
|
||||||
{
|
|
||||||
"e2e": {
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"devServerTarget": "my-app:serve:production",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"executor": "@nx/cypress:cypress",
|
|
||||||
"options": {
|
|
||||||
"cypressConfig": "my-app-e2e/cypress.json",
|
|
||||||
"devServerTarget": "my-app:serve",
|
|
||||||
"testingType": "e2e",
|
|
||||||
"tsConfig": "my-app-e2e/tsconfig.json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nx/eslint:lint",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project < v7 should update target configurations 1`] = `
|
|
||||||
{
|
|
||||||
"e2e": {
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"devServerTarget": "my-app:serve:production",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"executor": "@nx/cypress:cypress",
|
|
||||||
"options": {
|
|
||||||
"cypressConfig": "my-app-e2e/cypress.json",
|
|
||||||
"devServerTarget": "my-app:serve:development",
|
|
||||||
"testingType": "e2e",
|
|
||||||
"tsConfig": "my-app-e2e/tsconfig.json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nx/eslint:lint",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project > v10 for bundler:vite should pass the bundler info to nxE2EPreset in \`cypress.config.ts\` 1`] = `
|
|
||||||
"import { defineConfig } from 'cypress';
|
|
||||||
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
e2e: nxE2EPreset(__dirname, {
|
|
||||||
bundler: 'vite',
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project > v10 nested should set right path names in \`cypress.config.ts\` 1`] = `
|
|
||||||
"import { defineConfig } from 'cypress';
|
|
||||||
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
e2e: nxE2EPreset(__dirname),
|
|
||||||
});
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project > v10 nested should set right path names in \`tsconfig.e2e.json\` 1`] = `
|
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"allowJs": true,
|
|
||||||
"outDir": "../../dist/out-tsc",
|
|
||||||
"sourceMap": false,
|
|
||||||
"types": [
|
|
||||||
"cypress",
|
|
||||||
"node",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"extends": "../../tsconfig.base.json",
|
|
||||||
"include": [
|
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.js",
|
|
||||||
"cypress.config.ts",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project > v10 should set right path names in \`cypress.config.ts\` 1`] = `
|
|
||||||
"import { defineConfig } from 'cypress';
|
|
||||||
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
e2e: nxE2EPreset(__dirname),
|
|
||||||
});
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project > v10 should set right path names in \`tsconfig.e2e.json\` 1`] = `
|
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"allowJs": true,
|
|
||||||
"outDir": "../dist/out-tsc",
|
|
||||||
"sourceMap": false,
|
|
||||||
"types": [
|
|
||||||
"cypress",
|
|
||||||
"node",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"extends": "../tsconfig.base.json",
|
|
||||||
"include": [
|
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.js",
|
|
||||||
"cypress.config.ts",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`Cypress Project > v10 should update configuration when eslint is passed 1`] = `
|
|
||||||
"{
|
|
||||||
"extends": ["plugin:cypress/recommended", "../.eslintrc.json"],
|
|
||||||
"ignorePatterns": ["!**/*"],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
|
||||||
"rules": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
"
|
|
||||||
`;
|
|
||||||
@ -1,602 +0,0 @@
|
|||||||
import 'nx/src/internal-testing-utils/mock-project-graph';
|
|
||||||
|
|
||||||
import {
|
|
||||||
addProjectConfiguration,
|
|
||||||
readJson,
|
|
||||||
readProjectConfiguration,
|
|
||||||
Tree,
|
|
||||||
updateProjectConfiguration,
|
|
||||||
} from '@nx/devkit';
|
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
|
||||||
import { cypressProjectGenerator } from './cypress-project';
|
|
||||||
import { Schema } from './schema';
|
|
||||||
import { Linter } from '@nx/eslint';
|
|
||||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
|
||||||
import { cypressInitGenerator } from '../init/init';
|
|
||||||
|
|
||||||
jest.mock('../../utils/cypress-version');
|
|
||||||
jest.mock('../init/init');
|
|
||||||
describe('Cypress Project', () => {
|
|
||||||
let tree: Tree;
|
|
||||||
const defaultOptions: Omit<Schema, 'name' | 'project'> = {
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
};
|
|
||||||
let mockedInstalledCypressVersion: jest.Mock<
|
|
||||||
ReturnType<typeof installedCypressVersion>
|
|
||||||
> = installedCypressVersion as never;
|
|
||||||
let mockInitCypress: jest.Mock<ReturnType<typeof cypressInitGenerator>> =
|
|
||||||
cypressInitGenerator as never;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
||||||
|
|
||||||
addProjectConfiguration(tree, 'my-app', {
|
|
||||||
root: 'my-app',
|
|
||||||
targets: {
|
|
||||||
serve: {
|
|
||||||
executor: 'serve-executor',
|
|
||||||
options: {},
|
|
||||||
configurations: {
|
|
||||||
production: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
addProjectConfiguration(tree, 'my-dir-my-app', {
|
|
||||||
root: 'my-dir/my-app',
|
|
||||||
targets: {
|
|
||||||
serve: {
|
|
||||||
executor: 'serve-executor',
|
|
||||||
options: {},
|
|
||||||
configurations: {
|
|
||||||
production: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
afterEach(() => jest.clearAllMocks());
|
|
||||||
|
|
||||||
it('should call init if cypress is not installed', async () => {
|
|
||||||
mockedInstalledCypressVersion.mockReturnValue(null);
|
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockInitCypress).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call not init if cypress is installed', async () => {
|
|
||||||
mockedInstalledCypressVersion.mockReturnValue(10);
|
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockInitCypress).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('> v10', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
mockedInstalledCypressVersion.mockReturnValue(10);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate files for v10 and above', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.exists('my-app-e2e/cypress.config.ts')).toBeTruthy();
|
|
||||||
expect(tree.exists('my-app-e2e/src/fixtures/example.json')).toBeTruthy();
|
|
||||||
expect(tree.exists('my-app-e2e/src/e2e/app.cy.ts')).toBeTruthy();
|
|
||||||
expect(tree.exists('my-app-e2e/src/support/app.po.ts')).toBeTruthy();
|
|
||||||
expect(tree.exists('my-app-e2e/src/support/commands.ts')).toBeTruthy();
|
|
||||||
expect(tree.exists('my-app-e2e/src/support/e2e.ts')).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update configuration when eslint is passed', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.read('my-app-e2e/.eslintrc.json', 'utf-8')).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not add lint target when "none" is passed', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
linter: Linter.None,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, 'my-app-e2e');
|
|
||||||
expect(project.targets.lint).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update tags and implicit dependencies', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, 'my-app-e2e');
|
|
||||||
expect(project.tags).toEqual([]);
|
|
||||||
expect(project.implicitDependencies).toEqual(['my-app']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set right path names in `cypress.config.ts`', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const cypressConfig = tree.read('my-app-e2e/cypress.config.ts', 'utf-8');
|
|
||||||
expect(cypressConfig).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set right path names in `tsconfig.e2e.json`', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const tsconfigJson = readJson(tree, 'my-app-e2e/tsconfig.json');
|
|
||||||
expect(tsconfigJson).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should extend from tsconfig.base.json', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const tsConfig = readJson(tree, 'my-app-e2e/tsconfig.json');
|
|
||||||
expect(tsConfig.extends).toBe('../tsconfig.base.json');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support a root tsconfig.json instead of tsconfig.base.json', async () => {
|
|
||||||
tree.rename('tsconfig.base.json', 'tsconfig.json');
|
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const tsConfig = readJson(tree, 'my-app-e2e/tsconfig.json');
|
|
||||||
expect(tsConfig.extends).toBe('../tsconfig.json');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('for bundler:vite', () => {
|
|
||||||
it('should pass the bundler info to nxE2EPreset in `cypress.config.ts`', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
bundler: 'vite',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const cypressConfig = tree.read(
|
|
||||||
'my-app-e2e/cypress.config.ts',
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
expect(cypressConfig).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('nested', () => {
|
|
||||||
it('should set right path names in `cypress.config.ts`', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-dir-my-app',
|
|
||||||
directory: 'my-dir/my-app-e2e',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const cypressConfig = tree.read(
|
|
||||||
'my-dir/my-app-e2e/cypress.config.ts',
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
expect(cypressConfig).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set right path names in `tsconfig.e2e.json`', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-dir-my-app',
|
|
||||||
directory: 'my-dir/my-app-e2e',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const tsconfigJson = readJson(tree, 'my-dir/my-app-e2e/tsconfig.json');
|
|
||||||
expect(tsconfigJson).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should extend from tsconfig.base.json', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
directory: 'my-dir/my-app-e2e',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const tsConfig = readJson(tree, 'my-dir/my-app-e2e/tsconfig.json');
|
|
||||||
expect(tsConfig.extends).toBe('../../tsconfig.base.json');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support a root tsconfig.json instead of tsconfig.base.json', async () => {
|
|
||||||
tree.rename('tsconfig.base.json', 'tsconfig.json');
|
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
directory: 'my-dir/my-app-e2e',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const tsConfig = readJson(tree, 'my-dir/my-app-e2e/tsconfig.json');
|
|
||||||
expect(tsConfig.extends).toBe('../../tsconfig.json');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('root project', () => {
|
|
||||||
it('should generate in option.name when root project detected', async () => {
|
|
||||||
addProjectConfiguration(tree, 'root', { root: '.' });
|
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'e2e-tests',
|
|
||||||
baseUrl: 'http://localhost:1234',
|
|
||||||
project: 'root',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.listChanges().map((c) => c.path)).toEqual(
|
|
||||||
expect.arrayContaining([
|
|
||||||
'e2e-tests/cypress.config.ts',
|
|
||||||
'e2e-tests/src/e2e/app.cy.ts',
|
|
||||||
'e2e-tests/src/fixtures/example.json',
|
|
||||||
'e2e-tests/src/support/app.po.ts',
|
|
||||||
'e2e-tests/src/support/commands.ts',
|
|
||||||
'e2e-tests/src/support/e2e.ts',
|
|
||||||
'e2e-tests/tsconfig.json',
|
|
||||||
])
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not generate a root project when the passed in project is not the root project', async () => {
|
|
||||||
addProjectConfiguration(tree, 'root', { root: '.' });
|
|
||||||
addProjectConfiguration(tree, 'my-cool-app', { root: 'my-cool-app' });
|
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'e2e-tests',
|
|
||||||
baseUrl: 'http://localhost:1234',
|
|
||||||
project: 'my-cool-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.listChanges().map((c) => c.path)).toEqual(
|
|
||||||
expect.arrayContaining([
|
|
||||||
'e2e-tests/cypress.config.ts',
|
|
||||||
'e2e-tests/src/e2e/app.cy.ts',
|
|
||||||
'e2e-tests/src/fixtures/example.json',
|
|
||||||
'e2e-tests/src/support/app.po.ts',
|
|
||||||
'e2e-tests/src/support/commands.ts',
|
|
||||||
'e2e-tests/src/support/e2e.ts',
|
|
||||||
'e2e-tests/tsconfig.json',
|
|
||||||
])
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('--project', () => {
|
|
||||||
describe('none', () => {
|
|
||||||
it('should not add any implicit dependencies', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
baseUrl: 'http://localhost:7788',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-app-e2e');
|
|
||||||
expect(projectConfig.implicitDependencies).not.toBeDefined();
|
|
||||||
expect(projectConfig.tags).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not throw an error when --project does not have targets', async () => {
|
|
||||||
const projectConf = readProjectConfiguration(tree, 'my-app');
|
|
||||||
delete projectConf.targets;
|
|
||||||
updateProjectConfiguration(tree, 'my-app', projectConf);
|
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-app-e2e');
|
|
||||||
expect(projectConfig.targets['e2e'].options.devServerTarget).toEqual(
|
|
||||||
'my-app:serve'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate in the correct folder', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'one-two-other-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
directory: 'one/two/other-e2e',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, 'one-two-other-e2e');
|
|
||||||
expect(project).toBeDefined();
|
|
||||||
[
|
|
||||||
'one/two/other-e2e/cypress.config.ts',
|
|
||||||
'one/two/other-e2e/src/e2e/app.cy.ts',
|
|
||||||
].forEach((path) => expect(tree.exists(path)).toBeTruthy());
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate in the correct folder when --project-name-and-root-format=derived', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'other-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
directory: 'one/two',
|
|
||||||
projectNameAndRootFormat: 'derived',
|
|
||||||
});
|
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, 'one-two-other-e2e');
|
|
||||||
expect(project).toBeDefined();
|
|
||||||
[
|
|
||||||
'apps/one/two/other-e2e/cypress.config.ts',
|
|
||||||
'apps/one/two/other-e2e/src/e2e/app.cy.ts',
|
|
||||||
].forEach((path) => expect(tree.exists(path)).toBeTruthy());
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('serve-static', () => {
|
|
||||||
it('should configure Cypress with ci configuration if serve-static is found', async () => {
|
|
||||||
const appConfig = readProjectConfiguration(tree, 'my-app');
|
|
||||||
appConfig.targets['serve-static'] = {
|
|
||||||
executor: 'serve-static-executor',
|
|
||||||
options: {},
|
|
||||||
configurations: {
|
|
||||||
production: {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
updateProjectConfiguration(tree, 'my-app', appConfig);
|
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const e2eConfig = readProjectConfiguration(tree, 'my-app-e2e');
|
|
||||||
expect(e2eConfig.targets.e2e).toMatchObject({
|
|
||||||
options: {
|
|
||||||
devServerTarget: 'my-app:serve',
|
|
||||||
},
|
|
||||||
configurations: {
|
|
||||||
production: { devServerTarget: 'my-app:serve:production' },
|
|
||||||
ci: { devServerTarget: 'my-app:serve-static' },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not configure Cypress with ci configuration if serve-static is not found', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
const e2eConfig = readProjectConfiguration(tree, 'my-app-e2e');
|
|
||||||
expect(e2eConfig.targets.e2e.configurations.ci).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('v9 - v7', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
mockedInstalledCypressVersion.mockReturnValue(9);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate files', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.exists('my-app-e2e/cypress.json')).toBeTruthy();
|
|
||||||
expect(tree.exists('my-app-e2e/src/fixtures/example.json')).toBeTruthy();
|
|
||||||
expect(
|
|
||||||
tree.exists('my-app-e2e/src/integration/app.spec.ts')
|
|
||||||
).toBeTruthy();
|
|
||||||
expect(tree.exists('my-app-e2e/src/support/app.po.ts')).toBeTruthy();
|
|
||||||
expect(tree.exists('my-app-e2e/src/support/commands.ts')).toBeTruthy();
|
|
||||||
expect(tree.exists('my-app-e2e/src/support/index.ts')).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('< v7', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
mockedInstalledCypressVersion.mockReturnValue(6);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate a plugin file if cypress is below version 7', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
...defaultOptions,
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
addPlugin: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(tree.exists('my-app-e2e/src/plugins/index.js')).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update project configuration', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
addPlugin: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, 'my-app-e2e');
|
|
||||||
expect(project.root).toEqual('my-app-e2e');
|
|
||||||
expect(project.targets).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update project configuration (baseUrl)', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
baseUrl: 'http://localhost:3000',
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
addPlugin: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, 'my-app-e2e');
|
|
||||||
expect(project.root).toEqual('my-app-e2e');
|
|
||||||
expect(project.targets).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update target configurations', async () => {
|
|
||||||
const originalProject = readProjectConfiguration(tree, 'my-app');
|
|
||||||
originalProject.targets.serve.defaultConfiguration = 'development';
|
|
||||||
originalProject.targets.serve.configurations.development = {};
|
|
||||||
updateProjectConfiguration(tree, 'my-app', originalProject);
|
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
addPlugin: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, 'my-app-e2e');
|
|
||||||
expect(project.root).toEqual('my-app-e2e');
|
|
||||||
expect(project.targets).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('nested', () => {
|
|
||||||
it('should update configuration', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-dir-my-app-e2e',
|
|
||||||
project: 'my-dir-my-app',
|
|
||||||
directory: 'my-dir/my-app-e2e',
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
addPlugin: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const projectConfig = readProjectConfiguration(
|
|
||||||
tree,
|
|
||||||
'my-dir-my-app-e2e'
|
|
||||||
);
|
|
||||||
expect(projectConfig).toBeDefined();
|
|
||||||
expect(projectConfig.targets).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('--linter', () => {
|
|
||||||
describe('eslint', () => {
|
|
||||||
it('should add eslint-plugin-cypress', async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-app-e2e',
|
|
||||||
project: 'my-app',
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
addPlugin: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const packageJson = readJson(tree, 'package.json');
|
|
||||||
expect(
|
|
||||||
packageJson.devDependencies['eslint-plugin-cypress']
|
|
||||||
).toBeTruthy();
|
|
||||||
const eslintrcJson = readJson(tree, 'my-app-e2e/.eslintrc.json');
|
|
||||||
expect(eslintrcJson).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('project with directory in its name', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await cypressProjectGenerator(tree, {
|
|
||||||
name: 'my-dir-my-app-e2e',
|
|
||||||
project: 'my-dir-my-app',
|
|
||||||
directory: 'my-dir/my-app-e2e',
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
projectNameAndRootFormat: 'as-provided',
|
|
||||||
addPlugin: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update configuration', async () => {
|
|
||||||
const projectConfig = readProjectConfiguration(
|
|
||||||
tree,
|
|
||||||
'my-dir-my-app-e2e'
|
|
||||||
);
|
|
||||||
expect(projectConfig).toBeDefined();
|
|
||||||
expect(projectConfig.targets).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
|
||||||
const project = readProjectConfiguration(tree, 'my-dir-my-app-e2e');
|
|
||||||
expect(project.tags).toEqual([]);
|
|
||||||
expect(project.implicitDependencies).toEqual(['my-dir-my-app']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set right path names in `cypress.json`', async () => {
|
|
||||||
const cypressConfig = tree.read(
|
|
||||||
'my-dir/my-app-e2e/cypress.json',
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
expect(cypressConfig).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,297 +0,0 @@
|
|||||||
import {
|
|
||||||
addDependenciesToPackageJson,
|
|
||||||
addProjectConfiguration,
|
|
||||||
formatFiles,
|
|
||||||
generateFiles,
|
|
||||||
GeneratorCallback,
|
|
||||||
getProjects,
|
|
||||||
joinPathFragments,
|
|
||||||
logger,
|
|
||||||
offsetFromRoot,
|
|
||||||
ProjectConfiguration,
|
|
||||||
readProjectConfiguration,
|
|
||||||
runTasksInSerial,
|
|
||||||
stripIndents,
|
|
||||||
toJS,
|
|
||||||
Tree,
|
|
||||||
updateJson,
|
|
||||||
} from '@nx/devkit';
|
|
||||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
|
||||||
import { checkAndCleanWithSemver } from '@nx/devkit/src/utils/semver';
|
|
||||||
import {
|
|
||||||
getRelativePathToRootTsConfig,
|
|
||||||
initGenerator as jsInitGenerator,
|
|
||||||
} from '@nx/js';
|
|
||||||
import { Linter } from '@nx/eslint';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { major } from 'semver';
|
|
||||||
import { addLinterToCyProject } from '../../utils/add-linter';
|
|
||||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
|
||||||
import {
|
|
||||||
cypressVersion,
|
|
||||||
typesNodeVersion,
|
|
||||||
viteVersion,
|
|
||||||
} from '../../utils/versions';
|
|
||||||
import { cypressInitGenerator } from '../init/init';
|
|
||||||
import { Schema } from './schema';
|
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
|
||||||
|
|
||||||
export interface CypressProjectSchema extends Schema {
|
|
||||||
projectName: string;
|
|
||||||
projectRoot: string;
|
|
||||||
rootProject: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFiles(tree: Tree, options: CypressProjectSchema) {
|
|
||||||
// if not installed or >v10 use v10 folder
|
|
||||||
// else use v9 folder
|
|
||||||
const cypressVersion = installedCypressVersion();
|
|
||||||
const cypressFiles =
|
|
||||||
cypressVersion && cypressVersion < 10 ? 'v9-and-under' : 'v10-and-after';
|
|
||||||
|
|
||||||
generateFiles(
|
|
||||||
tree,
|
|
||||||
join(__dirname, './files', cypressFiles),
|
|
||||||
options.projectRoot,
|
|
||||||
{
|
|
||||||
tmpl: '',
|
|
||||||
...options,
|
|
||||||
project: options.project || 'Project',
|
|
||||||
ext: options.js ? 'js' : 'ts',
|
|
||||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
|
||||||
rootTsConfigPath: getRelativePathToRootTsConfig(
|
|
||||||
tree,
|
|
||||||
options.projectRoot
|
|
||||||
),
|
|
||||||
bundler: options.bundler,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cypressVersion && cypressVersion < 7) {
|
|
||||||
updateJson(tree, join(options.projectRoot, 'cypress.json'), (json) => {
|
|
||||||
json.pluginsFile = './src/plugins/index';
|
|
||||||
return json;
|
|
||||||
});
|
|
||||||
} else if (cypressVersion < 10) {
|
|
||||||
const pluginPath = join(options.projectRoot, 'src/plugins/index.js');
|
|
||||||
if (tree.exists(pluginPath)) {
|
|
||||||
tree.delete(pluginPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.js) {
|
|
||||||
toJS(tree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addProject(tree: Tree, options: CypressProjectSchema) {
|
|
||||||
let e2eProjectConfig: ProjectConfiguration;
|
|
||||||
|
|
||||||
const detectedCypressVersion =
|
|
||||||
installedCypressVersion() ??
|
|
||||||
major(checkAndCleanWithSemver('cypress', cypressVersion));
|
|
||||||
|
|
||||||
const cypressConfig =
|
|
||||||
detectedCypressVersion < 10 ? 'cypress.json' : 'cypress.config.ts';
|
|
||||||
|
|
||||||
if (options.baseUrl) {
|
|
||||||
e2eProjectConfig = {
|
|
||||||
root: options.projectRoot,
|
|
||||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
|
||||||
projectType: 'application',
|
|
||||||
targets: {
|
|
||||||
e2e: {
|
|
||||||
executor: '@nx/cypress:cypress',
|
|
||||||
options: {
|
|
||||||
cypressConfig: joinPathFragments(
|
|
||||||
options.projectRoot,
|
|
||||||
cypressConfig
|
|
||||||
),
|
|
||||||
baseUrl: options.baseUrl,
|
|
||||||
testingType: 'e2e',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tags: [],
|
|
||||||
implicitDependencies: options.project ? [options.project] : undefined,
|
|
||||||
};
|
|
||||||
} else if (options.project) {
|
|
||||||
const project = readProjectConfiguration(tree, options.project);
|
|
||||||
|
|
||||||
if (!project.targets) {
|
|
||||||
logger.warn(stripIndents`
|
|
||||||
NOTE: Project, "${options.project}", does not have any targets defined and a baseUrl was not provided. Nx will use
|
|
||||||
"${options.project}:serve" as the devServerTarget. But you may need to define this target within the project, "${options.project}".
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
const devServerTarget =
|
|
||||||
project.targets?.serve && project.targets?.serve?.defaultConfiguration
|
|
||||||
? `${options.project}:serve:${project.targets.serve.defaultConfiguration}`
|
|
||||||
: `${options.project}:serve`;
|
|
||||||
e2eProjectConfig = {
|
|
||||||
root: options.projectRoot,
|
|
||||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
|
||||||
projectType: 'application',
|
|
||||||
targets: {
|
|
||||||
e2e: {
|
|
||||||
executor: '@nx/cypress:cypress',
|
|
||||||
options: {
|
|
||||||
cypressConfig: joinPathFragments(
|
|
||||||
options.projectRoot,
|
|
||||||
cypressConfig
|
|
||||||
),
|
|
||||||
devServerTarget,
|
|
||||||
testingType: 'e2e',
|
|
||||||
},
|
|
||||||
configurations: {
|
|
||||||
production: {
|
|
||||||
devServerTarget: `${options.project}:serve:production`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tags: [],
|
|
||||||
implicitDependencies: options.project ? [options.project] : undefined,
|
|
||||||
};
|
|
||||||
if (project.targets?.['serve-static']) {
|
|
||||||
e2eProjectConfig.targets.e2e.configurations.ci = {
|
|
||||||
devServerTarget: `${options.project}:serve-static`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error(`Either project or baseUrl should be specified.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (detectedCypressVersion < 7) {
|
|
||||||
e2eProjectConfig.targets.e2e.options.tsConfig = joinPathFragments(
|
|
||||||
options.projectRoot,
|
|
||||||
'tsconfig.json'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
addProjectConfiguration(tree, options.projectName, e2eProjectConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use cypressE2EConfigurationGenerator instead
|
|
||||||
**/
|
|
||||||
export async function cypressProjectGenerator(host: Tree, schema: Schema) {
|
|
||||||
return await cypressProjectGeneratorInternal(host, {
|
|
||||||
projectNameAndRootFormat: 'derived',
|
|
||||||
addPlugin: false,
|
|
||||||
...schema,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use cypressE2EConfigurationGenerator instead
|
|
||||||
**/
|
|
||||||
export async function cypressProjectGeneratorInternal(
|
|
||||||
host: Tree,
|
|
||||||
schema: Schema
|
|
||||||
) {
|
|
||||||
const options = await normalizeOptions(host, schema);
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
|
||||||
const cypressVersion = installedCypressVersion();
|
|
||||||
// if there is an installed cypress version, then we don't call
|
|
||||||
// init since we want to keep the existing version that is installed
|
|
||||||
if (!cypressVersion) {
|
|
||||||
tasks.push(await jsInitGenerator(host, { ...options, skipFormat: true }));
|
|
||||||
tasks.push(
|
|
||||||
await cypressInitGenerator(host, {
|
|
||||||
...options,
|
|
||||||
skipFormat: true,
|
|
||||||
addPlugin: options.addPlugin,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
createFiles(host, options);
|
|
||||||
addProject(host, options);
|
|
||||||
const installTask = await addLinterToCyProject(host, {
|
|
||||||
...options,
|
|
||||||
cypressDir: 'src',
|
|
||||||
linter: schema.linter,
|
|
||||||
project: options.projectName,
|
|
||||||
overwriteExisting: true,
|
|
||||||
});
|
|
||||||
tasks.push(installTask);
|
|
||||||
|
|
||||||
if (!options.skipPackageJson) {
|
|
||||||
tasks.push(ensureDependencies(host, options));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
|
||||||
await formatFiles(host);
|
|
||||||
}
|
|
||||||
return runTasksInSerial(...tasks);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureDependencies(tree: Tree, options: CypressProjectSchema) {
|
|
||||||
const devDependencies: Record<string, string> = {
|
|
||||||
'@types/node': typesNodeVersion,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options.bundler === 'vite') {
|
|
||||||
devDependencies['vite'] = viteVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
return runTasksInSerial(
|
|
||||||
...[
|
|
||||||
addDependenciesToPackageJson(tree, {}, devDependencies),
|
|
||||||
() => {
|
|
||||||
logShowProjectCommand(options.projectName);
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function normalizeOptions(
|
|
||||||
host: Tree,
|
|
||||||
options: Schema
|
|
||||||
): Promise<CypressProjectSchema> {
|
|
||||||
let maybeRootProject: ProjectConfiguration;
|
|
||||||
let isRootProject = false;
|
|
||||||
|
|
||||||
const projects = getProjects(host);
|
|
||||||
// nx will set the project option for generators when ran within a project.
|
|
||||||
// since the root project will always be set for standalone projects we can just check it here.
|
|
||||||
if (options.project) {
|
|
||||||
maybeRootProject = projects.get(options.project);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
maybeRootProject?.root === '.' ||
|
|
||||||
// should still check to see if we are in a standalone based workspace
|
|
||||||
(!maybeRootProject &&
|
|
||||||
Array.from(projects.values()).some((config) => config.root === '.'))
|
|
||||||
) {
|
|
||||||
isRootProject = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { projectName, projectRoot } = await determineProjectNameAndRootOptions(
|
|
||||||
host,
|
|
||||||
{
|
|
||||||
name: options.name,
|
|
||||||
projectType: 'application',
|
|
||||||
directory: isRootProject ? options.name : options.directory,
|
|
||||||
projectNameAndRootFormat: isRootProject
|
|
||||||
? 'as-provided'
|
|
||||||
: options.projectNameAndRootFormat,
|
|
||||||
callingGenerator: '@nx/cypress:cypress-project',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
options.linter = options.linter || Linter.EsLint;
|
|
||||||
options.bundler = options.bundler || 'webpack';
|
|
||||||
options.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false';
|
|
||||||
|
|
||||||
return {
|
|
||||||
...options,
|
|
||||||
// other generators depend on the rootProject flag down stream
|
|
||||||
rootProject: isRootProject,
|
|
||||||
projectName,
|
|
||||||
projectRoot,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default cypressProjectGenerator;
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import { defineConfig } from 'cypress';
|
|
||||||
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
e2e: nxE2EPreset(__dirname<% if (bundler === 'vite'){ %>,
|
|
||||||
{
|
|
||||||
bundler: 'vite'
|
|
||||||
}
|
|
||||||
<% } %>)
|
|
||||||
});
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { getGreeting } from '../support/app.po';
|
|
||||||
|
|
||||||
describe('<%= project %>', () => {
|
|
||||||
beforeEach(() => cy.visit('/'));
|
|
||||||
|
|
||||||
it('should display welcome message', () => {
|
|
||||||
// Custom command example, see `../support/commands.ts` file
|
|
||||||
cy.login('my-email@something.com', 'myPassword');
|
|
||||||
|
|
||||||
// Function helper example, see `../support/app.po.ts` file
|
|
||||||
getGreeting().contains('Welcome <%= project %>');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Using fixtures to represent data",
|
|
||||||
"email": "hello@cypress.io"
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export const getGreeting = () => cy.get('h1');
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
// ***********************************************
|
|
||||||
// This example commands.js shows you how to
|
|
||||||
// create various custom commands and overwrite
|
|
||||||
// existing commands.
|
|
||||||
//
|
|
||||||
// For more comprehensive examples of custom
|
|
||||||
// commands please read more here:
|
|
||||||
// https://on.cypress.io/custom-commands
|
|
||||||
// ***********************************************
|
|
||||||
<% if (linter === 'eslint') { %>
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace<% } %>
|
|
||||||
declare namespace Cypress {<% if (linter === 'eslint') { %>
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars<% } %>
|
|
||||||
interface Chainable<Subject> {
|
|
||||||
login(email: string, password: string): void;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// -- This is a parent command --
|
|
||||||
Cypress.Commands.add('login', (email, password) => {
|
|
||||||
console.log('Custom command example: Login', email, password);
|
|
||||||
});
|
|
||||||
//
|
|
||||||
// -- This is a child command --
|
|
||||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a dual command --
|
|
||||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This will overwrite an existing command --
|
|
||||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
// ***********************************************************
|
|
||||||
// This example support/index.js is processed and
|
|
||||||
// loaded automatically before your test files.
|
|
||||||
//
|
|
||||||
// This is a great place to put global configuration and
|
|
||||||
// behavior that modifies Cypress.
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off
|
|
||||||
// automatically serving support files with the
|
|
||||||
// 'supportFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/configuration
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// Import commands.js using ES2015 syntax:
|
|
||||||
import './commands';
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "<%= rootTsConfigPath %>",
|
|
||||||
"compilerOptions": {
|
|
||||||
"sourceMap": false,
|
|
||||||
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
|
||||||
"allowJs": true,
|
|
||||||
"types": ["cypress", "node"]
|
|
||||||
},
|
|
||||||
"include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"]
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"fileServerFolder": ".",
|
|
||||||
"fixturesFolder": "./src/fixtures",
|
|
||||||
"integrationFolder": "./src/integration",
|
|
||||||
"modifyObstructiveCode": false,
|
|
||||||
"supportFile": "./src/support/index.<%= ext %>",
|
|
||||||
"pluginsFile": false,
|
|
||||||
"video": true,
|
|
||||||
"videosFolder": "<%= offsetFromRoot %>dist/cypress/<%= projectRoot %>/videos",
|
|
||||||
"screenshotsFolder": "<%= offsetFromRoot %>dist/cypress/<%= projectRoot %>/screenshots",
|
|
||||||
"chromeWebSecurity": false
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Using fixtures to represent data",
|
|
||||||
"email": "hello@cypress.io"
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { getGreeting } from '../support/app.po';
|
|
||||||
|
|
||||||
describe('<%= project %>', () => {
|
|
||||||
beforeEach(() => cy.visit('/'));
|
|
||||||
|
|
||||||
it('should display welcome message', () => {
|
|
||||||
// Custom command example, see `../support/commands.ts` file
|
|
||||||
cy.login('my-email@something.com', 'myPassword');
|
|
||||||
|
|
||||||
// Function helper example, see `../support/app.po.ts` file
|
|
||||||
getGreeting().contains('Welcome <%= project %>');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
// ***********************************************************
|
|
||||||
// This example plugins/index.js can be used to load plugins
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off loading
|
|
||||||
// the plugins file with the 'pluginsFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/plugins-guide
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// This function is called when a project is opened or re-opened (e.g. due to
|
|
||||||
// the project's config changing)
|
|
||||||
|
|
||||||
const { preprocessTypescript } = require('@nx/cypress/plugins/preprocessor');
|
|
||||||
|
|
||||||
module.exports = (on, config) => {
|
|
||||||
// `on` is used to hook into various events Cypress emits
|
|
||||||
// `config` is the resolved Cypress config
|
|
||||||
|
|
||||||
// Preprocess Typescript file using Nx helper
|
|
||||||
on('file:preprocessor', preprocessTypescript(config));
|
|
||||||
};
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export const getGreeting = () => cy.get('h1');
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
// ***********************************************
|
|
||||||
// This example commands.js shows you how to
|
|
||||||
// create various custom commands and overwrite
|
|
||||||
// existing commands.
|
|
||||||
//
|
|
||||||
// For more comprehensive examples of custom
|
|
||||||
// commands please read more here:
|
|
||||||
// https://on.cypress.io/custom-commands
|
|
||||||
// ***********************************************
|
|
||||||
<% if (linter === 'eslint') { %>
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-namespace<% } %>
|
|
||||||
declare namespace Cypress {<% if (linter === 'eslint') { %>
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars<% } %>
|
|
||||||
interface Chainable<Subject> {
|
|
||||||
login(email: string, password: string): void;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// -- This is a parent command --
|
|
||||||
Cypress.Commands.add('login', (email, password) => {
|
|
||||||
console.log('Custom command example: Login', email, password);
|
|
||||||
});
|
|
||||||
//
|
|
||||||
// -- This is a child command --
|
|
||||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This is a dual command --
|
|
||||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// -- This will overwrite an existing command --
|
|
||||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
// ***********************************************************
|
|
||||||
// This example support/index.ts is processed and
|
|
||||||
// loaded automatically before your test files.
|
|
||||||
//
|
|
||||||
// This is a great place to put global configuration and
|
|
||||||
// behavior that modifies Cypress.
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off
|
|
||||||
// automatically serving support files with the
|
|
||||||
// 'supportFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/configuration
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// Import commands.ts using ES2015 syntax:
|
|
||||||
import './commands';
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "<%= offsetFromRoot %>tsconfig.base.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"sourceMap": false,
|
|
||||||
"outDir": "<%= offsetFromRoot %>dist/out-tsc",
|
|
||||||
"allowJs": true,
|
|
||||||
"types": ["cypress", "node"]
|
|
||||||
},
|
|
||||||
"include": ["src/**/*.ts", "src/**/*.js"]
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
|
||||||
import type { Linter } from '@nx/eslint';
|
|
||||||
|
|
||||||
export interface Schema {
|
|
||||||
project?: string;
|
|
||||||
baseUrl?: string;
|
|
||||||
name: string;
|
|
||||||
directory?: string;
|
|
||||||
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
|
||||||
linter?: Linter;
|
|
||||||
js?: boolean;
|
|
||||||
skipFormat?: boolean;
|
|
||||||
setParserOptionsProject?: boolean;
|
|
||||||
skipPackageJson?: boolean;
|
|
||||||
bundler?: 'webpack' | 'vite' | 'none';
|
|
||||||
addPlugin?: boolean;
|
|
||||||
}
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json-schema.org/schema",
|
|
||||||
"$id": "NxCypressProjectGeneratorSchema",
|
|
||||||
"cli": "nx",
|
|
||||||
"title": "Create Cypress Configuration for the workspace",
|
|
||||||
"description": "Create Cypress Configuration for the workspace.",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"project": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The name of the frontend project to test.",
|
|
||||||
"$default": {
|
|
||||||
"$source": "projectName"
|
|
||||||
},
|
|
||||||
"x-priority": "important"
|
|
||||||
},
|
|
||||||
"baseUrl": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The address (with the port) which your application is running on."
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Name of the E2E Project.",
|
|
||||||
"$default": {
|
|
||||||
"$source": "argv",
|
|
||||||
"index": 0
|
|
||||||
},
|
|
||||||
"x-prompt": "What name would you like to use for the e2e project?"
|
|
||||||
},
|
|
||||||
"directory": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "A directory where the project is placed.",
|
|
||||||
"x-priority": "important"
|
|
||||||
},
|
|
||||||
"projectNameAndRootFormat": {
|
|
||||||
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["as-provided", "derived"]
|
|
||||||
},
|
|
||||||
"linter": {
|
|
||||||
"description": "The tool to use for running lint checks.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["eslint", "none"],
|
|
||||||
"default": "eslint"
|
|
||||||
},
|
|
||||||
"js": {
|
|
||||||
"description": "Generate JavaScript files rather than TypeScript files.",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
|
||||||
"description": "Skip formatting files.",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"x-priority": "internal"
|
|
||||||
},
|
|
||||||
"setParserOptionsProject": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"skipPackageJson": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"description": "Do not add dependencies to `package.json`.",
|
|
||||||
"x-priority": "internal"
|
|
||||||
},
|
|
||||||
"bundler": {
|
|
||||||
"description": "The Cypress bundler to use.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["vite", "webpack", "none"],
|
|
||||||
"x-prompt": "Which Cypress bundler do you want to use?",
|
|
||||||
"default": "webpack"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["name"],
|
|
||||||
"examplesFile": "../../../docs/cypress-project-examples.md"
|
|
||||||
}
|
|
||||||
@ -155,11 +155,6 @@ export default defineConfig({
|
|||||||
exports[`convertToCypressTen convertCypressProject should infer targets with --all flag 2`] = `
|
exports[`convertToCypressTen convertCypressProject should infer targets with --all flag 2`] = `
|
||||||
{
|
{
|
||||||
"e2e": {
|
"e2e": {
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"devServerTarget": "app:serve:production",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"executor": "@nx/cypress:cypress",
|
"executor": "@nx/cypress:cypress",
|
||||||
"options": {
|
"options": {
|
||||||
"cypressConfig": "app-e2e/cypress.config.ts",
|
"cypressConfig": "app-e2e/cypress.config.ts",
|
||||||
@ -168,11 +163,6 @@ exports[`convertToCypressTen convertCypressProject should infer targets with --a
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"e2e-custom": {
|
"e2e-custom": {
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"devServerTarget": "app:serve:production",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"executor": "@nx/cypress:cypress",
|
"executor": "@nx/cypress:cypress",
|
||||||
"options": {
|
"options": {
|
||||||
"cypressConfig": "app-e2e/cypress.config.ts",
|
"cypressConfig": "app-e2e/cypress.config.ts",
|
||||||
@ -212,11 +202,6 @@ export default defineConfig({
|
|||||||
exports[`convertToCypressTen convertCypressProject should not break when an invalid target is passed in 2`] = `
|
exports[`convertToCypressTen convertCypressProject should not break when an invalid target is passed in 2`] = `
|
||||||
{
|
{
|
||||||
"e2e": {
|
"e2e": {
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"devServerTarget": "app:serve:production",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"executor": "@nx/cypress:cypress",
|
"executor": "@nx/cypress:cypress",
|
||||||
"options": {
|
"options": {
|
||||||
"cypressConfig": "app-e2e/cypress.config.ts",
|
"cypressConfig": "app-e2e/cypress.config.ts",
|
||||||
@ -225,11 +210,6 @@ exports[`convertToCypressTen convertCypressProject should not break when an inva
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"e2e-custom": {
|
"e2e-custom": {
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"devServerTarget": "app:serve:production",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"executor": "@nx/cypress:cypress",
|
"executor": "@nx/cypress:cypress",
|
||||||
"options": {
|
"options": {
|
||||||
"cypressConfig": "app-e2e/cypress.config.ts",
|
"cypressConfig": "app-e2e/cypress.config.ts",
|
||||||
|
|||||||
@ -8,10 +8,11 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
import { installedCypressVersion } from '../../utils/cypress-version';
|
||||||
import { cypressProjectGenerator } from '../cypress-project/cypress-project';
|
import { configurationGenerator } from '../configuration/configuration';
|
||||||
import {
|
import {
|
||||||
createSupportFileImport,
|
createSupportFileImport,
|
||||||
updateImports,
|
updateImports,
|
||||||
@ -51,11 +52,23 @@ describe('convertToCypressTen', () => {
|
|||||||
});
|
});
|
||||||
mockedInstalledCypressVersion.mockReturnValue(9);
|
mockedInstalledCypressVersion.mockReturnValue(9);
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
addProjectConfiguration(tree, 'app-e2e', {
|
||||||
name: 'app-e2e',
|
projectType: 'application',
|
||||||
|
root: 'app-e2e',
|
||||||
|
sourceRoot: 'app-e2e/src',
|
||||||
|
targets: {},
|
||||||
|
implicitDependencies: ['app'],
|
||||||
|
tags: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
writeJson(tree, 'app-e2e/tsconfig.json', {
|
||||||
|
include: ['src/**/*.ts', 'src/**/*.js'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await configurationGenerator(tree, {
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
project: 'app',
|
project: 'app-e2e',
|
||||||
projectNameAndRootFormat: 'as-provided',
|
devServerTarget: 'app:serve',
|
||||||
addPlugin: false,
|
addPlugin: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -296,12 +309,26 @@ describe('convertToCypressTen', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await cypressProjectGenerator(tree, {
|
addProjectConfiguration(tree, 'app-two-e2e', {
|
||||||
name: 'app-two-e2e',
|
projectType: 'application',
|
||||||
skipFormat: true,
|
root: 'app-two-e2e',
|
||||||
project: 'app-two',
|
sourceRoot: 'app-two-e2e/src',
|
||||||
projectNameAndRootFormat: 'as-provided',
|
targets: {},
|
||||||
|
implicitDependencies: ['app-two'],
|
||||||
|
tags: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
writeJson(tree, 'app-two-e2e/tsconfig.json', {
|
||||||
|
include: ['src/**/*.ts', 'src/**/*.js'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await configurationGenerator(tree, {
|
||||||
|
skipFormat: true,
|
||||||
|
project: 'app-two-e2e',
|
||||||
|
devServerTarget: 'app-two:serve',
|
||||||
|
addPlugin: false,
|
||||||
|
});
|
||||||
|
|
||||||
const appOneProjectConfig = readProjectConfiguration(tree, 'app-e2e');
|
const appOneProjectConfig = readProjectConfiguration(tree, 'app-e2e');
|
||||||
appOneProjectConfig.targets['e2e'].options.cypressConfig = 'cypress.json';
|
appOneProjectConfig.targets['e2e'].options.cypressConfig = 'cypress.json';
|
||||||
updateProjectConfiguration(tree, 'app-e2e', appOneProjectConfig);
|
updateProjectConfiguration(tree, 'app-e2e', appOneProjectConfig);
|
||||||
@ -338,11 +365,6 @@ describe('convertToCypressTen', () => {
|
|||||||
devServerTarget: 'app:serve',
|
devServerTarget: 'app:serve',
|
||||||
testingType: 'e2e',
|
testingType: 'e2e',
|
||||||
},
|
},
|
||||||
configurations: {
|
|
||||||
production: {
|
|
||||||
devServerTarget: 'app:serve:production',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
expect(readJson(tree, 'app-two-e2e/tsconfig.json').include).toEqual([
|
expect(readJson(tree, 'app-two-e2e/tsconfig.json').include).toEqual([
|
||||||
'src/**/*.ts',
|
'src/**/*.ts',
|
||||||
@ -360,11 +382,6 @@ describe('convertToCypressTen', () => {
|
|||||||
devServerTarget: 'app-two:serve',
|
devServerTarget: 'app-two:serve',
|
||||||
testingType: 'e2e',
|
testingType: 'e2e',
|
||||||
},
|
},
|
||||||
configurations: {
|
|
||||||
production: {
|
|
||||||
devServerTarget: 'app-two:serve:production',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,15 +1,8 @@
|
|||||||
// Prevent sensitive keys from being bundled when source code uses entire `process.env` object rather than individual keys (e.g. `process.env.NX_FOO`).
|
|
||||||
// TODO(v19): Only env vars prefixed with NX_PUBLIC should be bundled. This is a breaking change so we won't do it in v18.
|
|
||||||
const excludedKeys = ['NX_CLOUD_ACCESS_TOKEN', 'NX_CLOUD_ENCRYPTION_KEY'];
|
|
||||||
|
|
||||||
export function getClientEnvironment(): Record<string, string> {
|
export function getClientEnvironment(): Record<string, string> {
|
||||||
const NX_APP = /^NX_/i;
|
const nxPublicKeyRegex = /^NX_PUBLIC_/i;
|
||||||
|
|
||||||
return Object.keys(process.env)
|
return Object.keys(process.env)
|
||||||
.filter(
|
.filter((key) => nxPublicKeyRegex.test(key) || key === 'NODE_ENV')
|
||||||
(key) =>
|
|
||||||
!excludedKeys.includes(key) && (NX_APP.test(key) || key === 'NODE_ENV')
|
|
||||||
)
|
|
||||||
.reduce((env, key) => {
|
.reduce((env, key) => {
|
||||||
env[`process.env.${key}`] = JSON.stringify(process.env[key]);
|
env[`process.env.${key}`] = JSON.stringify(process.env[key]);
|
||||||
return env;
|
return env;
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export default {
|
|||||||
* previously defined v5 of `@typescript-eslint`. v6 of `@typescript-eslint`
|
* previously defined v5 of `@typescript-eslint`. v6 of `@typescript-eslint`
|
||||||
* changed how configurations are defined.
|
* changed how configurations are defined.
|
||||||
*
|
*
|
||||||
* TODO(v19): re-evalute these deviations from @typescript-eslint/recommended in v19 of Nx
|
* TODO(v20): re-evalute these deviations from @typescript-eslint/recommended in v19 of Nx
|
||||||
*/
|
*/
|
||||||
'no-extra-semi': 'off',
|
'no-extra-semi': 'off',
|
||||||
'@typescript-eslint/no-extra-semi': 'error',
|
'@typescript-eslint/no-extra-semi': 'error',
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export default {
|
|||||||
* previously defined v5 of `@typescript-eslint`. v6 of `@typescript-eslint`
|
* previously defined v5 of `@typescript-eslint`. v6 of `@typescript-eslint`
|
||||||
* changed how configurations are defined.
|
* changed how configurations are defined.
|
||||||
*
|
*
|
||||||
* TODO(v19): re-evalute these deviations from @typescript-eslint/recommended in v19 of Nx
|
* TODO(v20): re-evalute these deviations from @typescript-eslint/recommended in v19 of Nx
|
||||||
*/
|
*/
|
||||||
'no-extra-semi': 'off',
|
'no-extra-semi': 'off',
|
||||||
'@typescript-eslint/no-extra-semi': 'error',
|
'@typescript-eslint/no-extra-semi': 'error',
|
||||||
|
|||||||
@ -65,6 +65,12 @@
|
|||||||
"version": "18.0.0-beta.0",
|
"version": "18.0.0-beta.0",
|
||||||
"description": "Remove the offset from the outputDir of the export target",
|
"description": "Remove the offset from the outputDir of the export target",
|
||||||
"implementation": "./src/migrations/update-18-0-0/change-outputDir-export-target"
|
"implementation": "./src/migrations/update-18-0-0/change-outputDir-export-target"
|
||||||
|
},
|
||||||
|
"update-19-0-0-change-webpack-to-metro": {
|
||||||
|
"version": "19.0.0-beta.9",
|
||||||
|
"cli": "nx",
|
||||||
|
"description": "Change webpack to metro in expo projects",
|
||||||
|
"factory": "./src/migrations/update-19-0-0/change-webpack-to-metro"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packageJsonUpdates": {
|
"packageJsonUpdates": {
|
||||||
|
|||||||
@ -35,7 +35,6 @@
|
|||||||
"node-fetch": "^2.6.7",
|
"node-fetch": "^2.6.7",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"tsconfig-paths": "^4.1.2",
|
"tsconfig-paths": "^4.1.2",
|
||||||
"tsconfig-paths-webpack-plugin": "^4.0.0",
|
|
||||||
"@nx/jest": "file:../jest",
|
"@nx/jest": "file:../jest",
|
||||||
"@nx/js": "file:../js",
|
"@nx/js": "file:../js",
|
||||||
"@nx/eslint": "file:../eslint",
|
"@nx/eslint": "file:../eslint",
|
||||||
|
|||||||
@ -1,54 +0,0 @@
|
|||||||
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
|
||||||
import { resolve } from 'path';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated TODO(v19) use bundler: 'metro' instead, will be removed in v19
|
|
||||||
* This function add additional rules to expo's webpack config to make expo web working
|
|
||||||
*/
|
|
||||||
export async function withNxWebpack(config) {
|
|
||||||
// add additional rule to load files under libs
|
|
||||||
const rules = config.module.rules.find((rule) =>
|
|
||||||
Array.isArray(rule.oneOf)
|
|
||||||
)?.oneOf;
|
|
||||||
if (rules) {
|
|
||||||
rules.push({
|
|
||||||
test: /\.(mjs|[jt]sx?)$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: require.resolve('@nx/webpack/src/utils/web-babel-loader.js'),
|
|
||||||
options: {
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
'@nx/react/babel',
|
|
||||||
{
|
|
||||||
runtime: 'automatic',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.resolve) {
|
|
||||||
config.resolve = {};
|
|
||||||
}
|
|
||||||
if (!config.resolve.plugins) {
|
|
||||||
config.resolve.plugins = [];
|
|
||||||
}
|
|
||||||
const extensions = ['.ts', '.tsx', '.mjs', '.js', '.jsx'];
|
|
||||||
const tsConfigPath = resolve(__dirname, 'tsconfig.json');
|
|
||||||
config.resolve.plugins.push(
|
|
||||||
new TsconfigPathsPlugin({
|
|
||||||
configFile: tsConfigPath,
|
|
||||||
extensions,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
config.resolve.fallback = {
|
|
||||||
...config.resolve.fallback,
|
|
||||||
crypto: require.resolve('crypto-browserify'),
|
|
||||||
stream: require.resolve('stream-browserify'),
|
|
||||||
};
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
import {
|
||||||
|
addProjectConfiguration,
|
||||||
|
getProjects,
|
||||||
|
readJson,
|
||||||
|
Tree,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
|
import update from './change-webpack-to-metro';
|
||||||
|
|
||||||
|
describe('change-webpack-to-metro', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
|
addProjectConfiguration(tree, 'product', {
|
||||||
|
root: 'apps/product',
|
||||||
|
sourceRoot: 'apps/product/src',
|
||||||
|
targets: {
|
||||||
|
start: {
|
||||||
|
executor: '@nx/expo:start',
|
||||||
|
},
|
||||||
|
'export-web': {
|
||||||
|
executor: '@nx/expo:export',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
tree.write(
|
||||||
|
`apps/product/app.json`,
|
||||||
|
JSON.stringify({
|
||||||
|
expo: {
|
||||||
|
web: {
|
||||||
|
bundler: 'webpack',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should update project.json with target export-web and change app.json`, async () => {
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
getProjects(tree).forEach((project) => {
|
||||||
|
expect(project.targets['export-web']).toEqual({
|
||||||
|
executor: '@nx/expo:export',
|
||||||
|
options: {
|
||||||
|
bundler: 'metro',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(project.targets['web']).toBeUndefined();
|
||||||
|
const appJson = readJson(tree, `apps/product/app.json`);
|
||||||
|
expect(appJson.expo.web.bundler).toEqual('metro');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
Tree,
|
||||||
|
formatFiles,
|
||||||
|
getProjects,
|
||||||
|
updateProjectConfiguration,
|
||||||
|
updateJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migration:
|
||||||
|
* - change target 'export-web'
|
||||||
|
* - change bundler to 'metro'
|
||||||
|
*/
|
||||||
|
export default async function update(tree: Tree) {
|
||||||
|
const projects = getProjects(tree);
|
||||||
|
|
||||||
|
for (const [name, config] of projects.entries()) {
|
||||||
|
if (config.targets?.['start']?.executor === '@nx/expo:start') {
|
||||||
|
if (config.targets['web']) {
|
||||||
|
delete config.targets['web'];
|
||||||
|
}
|
||||||
|
if (config.targets['export-web']) {
|
||||||
|
config.targets['export-web'].options.bundler = 'metro';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateJson(tree, `${config.root}/app.json`, (appJson) => {
|
||||||
|
if (appJson.expo?.web) {
|
||||||
|
appJson.expo.web.bundler = 'metro';
|
||||||
|
}
|
||||||
|
return appJson;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProjectConfiguration(tree, name, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
await formatFiles(tree);
|
||||||
|
}
|
||||||
@ -37,7 +37,7 @@ module.exports = function (api: any, options: NxWebBabelPresetOptions = {}) {
|
|||||||
|
|
||||||
// Determine settings for `@babel//babel-plugin-transform-class-properties`,
|
// Determine settings for `@babel//babel-plugin-transform-class-properties`,
|
||||||
// so that we can sync the `loose` option with `@babel/preset-env`.
|
// so that we can sync the `loose` option with `@babel/preset-env`.
|
||||||
// TODO(v19): Remove classProperties since it's no longer needed, now that the class props transform is in preset-env.
|
// TODO(v20): Remove classProperties since it's no longer needed, now that the class props transform is in preset-env.
|
||||||
const loose = options.classProperties?.loose ?? options.loose ?? true;
|
const loose = options.classProperties?.loose ?? options.loose ?? true;
|
||||||
if (options.classProperties) {
|
if (options.classProperties) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
|
|||||||
@ -327,12 +327,7 @@ export function getNextConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 5. Add env variables prefixed with NX_
|
* 5. Add SVGR support if option is on.
|
||||||
*/
|
|
||||||
addNxEnvVariables(config);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 6. Add SVGR support if option is on.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Default SVGR support to be on for projects.
|
// Default SVGR support to be on for projects.
|
||||||
@ -393,40 +388,6 @@ export function getNextConfig(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent sensitive keys from being bundled when source code uses entire `process.env` object rather than individual keys (e.g. `process.env.NX_FOO`).
|
|
||||||
// TODO(v19): BREAKING: Only support NEXT_PUBLIC_ env vars and ignore NX_ vars since this is a standard Next.js feature.
|
|
||||||
const excludedKeys = ['NX_CLOUD_ACCESS_TOKEN', 'NX_CLOUD_ENCRYPTION_KEY'];
|
|
||||||
|
|
||||||
function getNxEnvironmentVariables() {
|
|
||||||
return Object.keys(process.env)
|
|
||||||
.filter((env) => !excludedKeys.includes(env) && /^NX_/i.test(env))
|
|
||||||
.reduce((env, key) => {
|
|
||||||
env[key] = process.env[key];
|
|
||||||
return env;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO(v19)
|
|
||||||
* @deprecated Use Next.js 9.4+ built-in support for environment variables. Reference https://nextjs.org/docs/pages/api-reference/next-config-js/env
|
|
||||||
*/
|
|
||||||
function addNxEnvVariables(config: any) {
|
|
||||||
const maybeDefinePlugin = config.plugins?.find((plugin) => {
|
|
||||||
return plugin.definitions?.['process.env.NODE_ENV'];
|
|
||||||
});
|
|
||||||
|
|
||||||
if (maybeDefinePlugin) {
|
|
||||||
const env = getNxEnvironmentVariables();
|
|
||||||
|
|
||||||
Object.entries(env)
|
|
||||||
.map(([name, value]) => [`process.env.${name}`, `"${value}"`])
|
|
||||||
.filter(([name]) => !maybeDefinePlugin.definitions[name])
|
|
||||||
.forEach(
|
|
||||||
([name, value]) => (maybeDefinePlugin.definitions[name] = value)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAliasForProject(
|
export function getAliasForProject(
|
||||||
node: ProjectGraphProjectNode,
|
node: ProjectGraphProjectNode,
|
||||||
paths: Record<string, string[]>
|
paths: Record<string, string[]>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { NextConfigFn } from '../src/utils/config';
|
import { NextConfigFn } from '../src/utils/config';
|
||||||
import { WithNxOptions } from './with-nx';
|
import { WithNxOptions } from './with-nx';
|
||||||
|
|
||||||
// TODO(v19): Remove file, it is here until users migrate over to SASS manually.
|
// TODO(v20): Remove file, it is here until users migrate over to SASS manually.
|
||||||
export function withStylus(
|
export function withStylus(
|
||||||
configOrFn: WithNxOptions | NextConfigFn
|
configOrFn: WithNxOptions | NextConfigFn
|
||||||
): NextConfigFn {
|
): NextConfigFn {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ interface Schema {
|
|||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(v19): Remove this logic once we no longer derive directory.
|
// TODO(v20): Remove this logic once we no longer derive directory.
|
||||||
function maybeGetDerivedDirectory(host: Tree, options: Schema): string {
|
function maybeGetDerivedDirectory(host: Tree, options: Schema): string {
|
||||||
if (!options.project) return options.directory;
|
if (!options.project) return options.directory;
|
||||||
const workspace = getProjects(host);
|
const workspace = getProjects(host);
|
||||||
|
|||||||
@ -56,7 +56,7 @@ async function normalizeOptions(host: Tree, options: Schema) {
|
|||||||
|
|
||||||
if (options.project) {
|
if (options.project) {
|
||||||
// Legacy behavior, detect app vs page router from specified project.
|
// Legacy behavior, detect app vs page router from specified project.
|
||||||
// TODO(v19): remove this logic
|
// TODO(v20): remove this logic
|
||||||
const project = readProjectConfiguration(host, options.project);
|
const project = readProjectConfiguration(host, options.project);
|
||||||
// app/ is a reserved folder in nextjs so it is safe to check it's existence
|
// app/ is a reserved folder in nextjs so it is safe to check it's existence
|
||||||
isAppRouter =
|
isAppRouter =
|
||||||
|
|||||||
@ -283,7 +283,10 @@ function buildTargetWebpack(
|
|||||||
|
|
||||||
return async () => {
|
return async () => {
|
||||||
customWebpack = await customWebpack;
|
customWebpack = await customWebpack;
|
||||||
// TODO(v19): Once webpackConfig is always set in @nx/webpack:webpack and isolatedConfig is removed, we no longer need this default.
|
// TODO(v20): Component testing need to be agnostic of the underlying executor. With Crystal, we're not using `@nx/webpack:webpack` by default.
|
||||||
|
// We need to decouple CT from the build target of the app, we just care about bundler config (e.g. webpack.config.js).
|
||||||
|
// The generated setup should support both Webpack and Vite as documented here: https://docs.cypress.io/guides/component-testing/react/overview
|
||||||
|
// Related issue: https://github.com/nrwl/nx/issues/21546
|
||||||
const configure = composePluginsSync(withNx(), withWeb());
|
const configure = composePluginsSync(withNx(), withWeb());
|
||||||
const defaultWebpack = configure(
|
const defaultWebpack = configure(
|
||||||
{},
|
{},
|
||||||
|
|||||||
@ -18,24 +18,16 @@ import { mergePlugins } from './merge-plugins';
|
|||||||
import { withReact } from '../with-react';
|
import { withReact } from '../with-react';
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
|
|
||||||
// Prevent sensitive keys from being bundled when source code uses entire `process.env` object rather than individual keys (e.g. `process.env.NX_FOO`).
|
|
||||||
// TODO(v19): BREAKING: Only env vars prefixed with NX_PUBLIC should be bundled. This is a breaking change so we won't do it in v18.
|
|
||||||
const excludedKeys = ['NX_CLOUD_ACCESS_TOKEN', 'NX_CLOUD_ENCRYPTION_KEY'];
|
|
||||||
|
|
||||||
// This is shamelessly taken from CRA and modified for NX use
|
// This is shamelessly taken from CRA and modified for NX use
|
||||||
// https://github.com/facebook/create-react-app/blob/4784997f0682e75eb32a897b4ffe34d735912e6c/packages/react-scripts/config/env.js#L71
|
// https://github.com/facebook/create-react-app/blob/4784997f0682e75eb32a897b4ffe34d735912e6c/packages/react-scripts/config/env.js#L71
|
||||||
function getClientEnvironment(mode) {
|
function getClientEnvironment(mode) {
|
||||||
// Grab NODE_ENV and NX_* and STORYBOOK_* environment variables and prepare them to be
|
// Grab NODE_ENV and NX_* and STORYBOOK_* environment variables and prepare them to be
|
||||||
// injected into the application via DefinePlugin in webpack configuration.
|
// injected into the application via DefinePlugin in webpack configuration.
|
||||||
const NX_PREFIX = /^NX_/i;
|
const NX_PREFIX = /^NX_PUBLIC_/i;
|
||||||
const STORYBOOK_PREFIX = /^STORYBOOK_/i;
|
const STORYBOOK_PREFIX = /^STORYBOOK_/i;
|
||||||
|
|
||||||
const raw = Object.keys(process.env)
|
const raw = Object.keys(process.env)
|
||||||
.filter(
|
.filter((key) => NX_PREFIX.test(key) || STORYBOOK_PREFIX.test(key))
|
||||||
(key) =>
|
|
||||||
!excludedKeys.includes(key) &&
|
|
||||||
(NX_PREFIX.test(key) || STORYBOOK_PREFIX.test(key))
|
|
||||||
)
|
|
||||||
.reduce(
|
.reduce(
|
||||||
(env, key) => {
|
(env, key) => {
|
||||||
env[key] = process.env[key];
|
env[key] = process.env[key];
|
||||||
|
|||||||
@ -5,21 +5,17 @@ description: Examples and a short guide on how to use the @nx/webpack:webpack bu
|
|||||||
|
|
||||||
`project.json`:
|
`project.json`:
|
||||||
|
|
||||||
```json
|
```json5
|
||||||
//...
|
//...
|
||||||
"my-app": {
|
"my-app": {
|
||||||
"targets": {
|
"targets": {
|
||||||
//...
|
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "@nx/webpack:webpack",
|
"executor": "@nx/webpack:webpack",
|
||||||
//...
|
|
||||||
//...
|
|
||||||
"options": {
|
"options": {
|
||||||
...
|
"webpackConfig": "apps/my-app/webpack.config.js"
|
||||||
},
|
|
||||||
//...
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
//...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -40,21 +36,19 @@ Copying from the [Babel documentation](https://babeljs.io/docs/config-files#root
|
|||||||
|
|
||||||
Setting `babelUpwardRootMode` to `true` in your `project.json` will set `rootMode` option to `upward` in the Babel config. You may want the `upward` mode in a monorepo when projects must apply their individual `.babelrc` file. We recommend that you don't set it at all, so it will use the default to `false` as the `upward` mode brings additional complexity to the build process.
|
Setting `babelUpwardRootMode` to `true` in your `project.json` will set `rootMode` option to `upward` in the Babel config. You may want the `upward` mode in a monorepo when projects must apply their individual `.babelrc` file. We recommend that you don't set it at all, so it will use the default to `false` as the `upward` mode brings additional complexity to the build process.
|
||||||
|
|
||||||
```json
|
```json5
|
||||||
//...
|
//...
|
||||||
"my-app": {
|
"my-app": {
|
||||||
"targets": {
|
"targets": {
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "@nx/webpack:webpack",
|
"executor": "@nx/webpack:webpack",
|
||||||
"options": {
|
"options": {
|
||||||
"babelUpwardRootMode": true,
|
"webpackConfig": "apps/my-app/webpack.config.js",
|
||||||
//...
|
"babelUpwardRootMode": true
|
||||||
},
|
}
|
||||||
//...
|
|
||||||
},
|
|
||||||
//...
|
|
||||||
},
|
},
|
||||||
//...
|
//...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -94,22 +88,18 @@ In workspace above, if `demo` imports `a` and `b`, it will apply the config `lib
|
|||||||
|
|
||||||
If you have a custom Babel config file (i.e. not `.babelrc`), you can use the `configFile` option as follows:
|
If you have a custom Babel config file (i.e. not `.babelrc`), you can use the `configFile` option as follows:
|
||||||
|
|
||||||
```json
|
```json5
|
||||||
//...
|
//...
|
||||||
"my-app": {
|
"my-app": {
|
||||||
"targets": {
|
"targets": {
|
||||||
//...
|
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "@nx/webpack:webpack",
|
"executor": "@nx/webpack:webpack",
|
||||||
//...
|
|
||||||
"options": {
|
"options": {
|
||||||
//...
|
"webpackConfig": "apps/my-app/webpack.config.js",
|
||||||
"babelConfig": "apps/my-app/.babelrc.custom.json",
|
"babelConfig": "apps/my-app/.babelrc.custom.json",
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
...
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -134,17 +124,11 @@ Set `isolatedConfig` to `true` in your `project.json` file in the `build` target
|
|||||||
//...
|
//...
|
||||||
"my-app": {
|
"my-app": {
|
||||||
"targets": {
|
"targets": {
|
||||||
//...
|
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "@nx/webpack:webpack",
|
"executor": "@nx/webpack:webpack",
|
||||||
//...
|
|
||||||
"options": {
|
"options": {
|
||||||
//...
|
|
||||||
"webpackConfig": "apps/my-app/webpack.config.js",
|
"webpackConfig": "apps/my-app/webpack.config.js",
|
||||||
"isolatedConfig": true
|
"isolatedConfig": true
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
...
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ export interface WebpackExecutorOptions {
|
|||||||
extractLicenses?: boolean;
|
extractLicenses?: boolean;
|
||||||
fileReplacements?: FileReplacement[];
|
fileReplacements?: FileReplacement[];
|
||||||
generatePackageJson?: boolean;
|
generatePackageJson?: boolean;
|
||||||
// TODO(v19): Remove this option
|
// TODO(v20): Remove this option
|
||||||
/** @deprecated set webpackConfig and provide an explicit webpack.config.js file (See: https://nx.dev/recipes/webpack/webpack-config-setup) */
|
/** @deprecated set webpackConfig and provide an explicit webpack.config.js file (See: https://nx.dev/recipes/webpack/webpack-config-setup) */
|
||||||
isolatedConfig?: boolean;
|
isolatedConfig?: boolean;
|
||||||
standardWebpackConfigFunction?: boolean;
|
standardWebpackConfigFunction?: boolean;
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
// Prevent sensitive keys from being bundled when source code uses entire `process.env` object rather than individual keys (e.g. `process.env.NX_FOO`).
|
|
||||||
// TODO(v19): Only env vars prefixed with NX_PUBLIC should be bundled. This is a breaking change so we won't do it in v18.
|
|
||||||
const excludedKeys = ['NX_CLOUD_ACCESS_TOKEN', 'NX_CLOUD_ENCRYPTION_KEY'];
|
|
||||||
|
|
||||||
export function getClientEnvironment(mode?: string) {
|
export function getClientEnvironment(mode?: string) {
|
||||||
// Grab NODE_ENV and NX_* environment variables and prepare them to be
|
// Grab NODE_ENV and NX_PUBLIC_* environment variables and prepare them to be
|
||||||
// injected into the application via DefinePlugin in webpack configuration.
|
// injected into the application via DefinePlugin in webpack configuration.
|
||||||
const NX_APP = /^NX_/i;
|
const nxPublicKeyRegex = /^NX_PUBLIC_/i;
|
||||||
|
|
||||||
const raw = Object.keys(process.env)
|
const raw = Object.keys(process.env)
|
||||||
.filter((key) => !excludedKeys.includes(key) && NX_APP.test(key))
|
.filter((key) => nxPublicKeyRegex.test(key))
|
||||||
.reduce(
|
.reduce(
|
||||||
(env, key) => {
|
(env, key) => {
|
||||||
env[key] = process.env[key];
|
env[key] = process.env[key];
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { interpolateEnvironmentVariablesToIndex } from './interpolate-env-variab
|
|||||||
|
|
||||||
describe('interpolateEnvironmentVariablesToIndex()', () => {
|
describe('interpolateEnvironmentVariablesToIndex()', () => {
|
||||||
const envDefaults = {
|
const envDefaults = {
|
||||||
NX_VARIABLE: 'foo',
|
NX_PUBLIC_VARIABLE: 'foo',
|
||||||
SOME_OTHER_VARIABLE: 'bar',
|
SOME_OTHER_VARIABLE: 'bar',
|
||||||
DEPLOY_URL: 'baz',
|
DEPLOY_URL: 'baz',
|
||||||
};
|
};
|
||||||
@ -14,7 +14,7 @@ describe('interpolateEnvironmentVariablesToIndex()', () => {
|
|||||||
|
|
||||||
test('default env variables', () => {
|
test('default env variables', () => {
|
||||||
const content = `
|
const content = `
|
||||||
<div>Nx Variable: %NX_VARIABLE%</div>
|
<div>Nx Variable: %NX_PUBLIC_VARIABLE%</div>
|
||||||
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
||||||
<div>Deploy Url: %DEPLOY_URL%</div>
|
<div>Deploy Url: %DEPLOY_URL%</div>
|
||||||
`;
|
`;
|
||||||
@ -28,7 +28,7 @@ describe('interpolateEnvironmentVariablesToIndex()', () => {
|
|||||||
|
|
||||||
test('Deploy url set as option overrides DEPLOY_URL env variable', () => {
|
test('Deploy url set as option overrides DEPLOY_URL env variable', () => {
|
||||||
const content = `
|
const content = `
|
||||||
<div>Nx Variable: %NX_VARIABLE%</div>
|
<div>Nx Variable: %NX_PUBLIC_VARIABLE%</div>
|
||||||
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
||||||
<div>Deploy Url: %DEPLOY_URL%</div>
|
<div>Deploy Url: %DEPLOY_URL%</div>
|
||||||
`;
|
`;
|
||||||
@ -45,7 +45,7 @@ describe('interpolateEnvironmentVariablesToIndex()', () => {
|
|||||||
test('No deploy url provided via either option', () => {
|
test('No deploy url provided via either option', () => {
|
||||||
delete process.env.DEPLOY_URL;
|
delete process.env.DEPLOY_URL;
|
||||||
const content = `
|
const content = `
|
||||||
<div>Nx Variable: %NX_VARIABLE%</div>
|
<div>Nx Variable: %NX_PUBLIC_VARIABLE%</div>
|
||||||
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
||||||
<div>Deploy Url: %DEPLOY_URL%</div>
|
<div>Deploy Url: %DEPLOY_URL%</div>
|
||||||
`;
|
`;
|
||||||
@ -60,7 +60,7 @@ describe('interpolateEnvironmentVariablesToIndex()', () => {
|
|||||||
test('NX_ prefixed option present in index.html, but not present in process.env', () => {
|
test('NX_ prefixed option present in index.html, but not present in process.env', () => {
|
||||||
delete process.env.DEPLOY_URL;
|
delete process.env.DEPLOY_URL;
|
||||||
const content = `
|
const content = `
|
||||||
<div>Nx Variable: %NX_VARIABLE%</div>
|
<div>Nx Variable: %NX_PUBLIC_VARIABLE%</div>
|
||||||
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
<div>Some other variable: %SOME_OTHER_VARIABLE%</div>
|
||||||
<div>Some other nx_variable: %NX_SOME_OTHER_VARIABLE%</div>
|
<div>Some other nx_variable: %NX_SOME_OTHER_VARIABLE%</div>
|
||||||
<div>Deploy Url: %DEPLOY_URL%</div>
|
<div>Deploy Url: %DEPLOY_URL%</div>
|
||||||
|
|||||||
@ -6,14 +6,10 @@ export function interpolateEnvironmentVariablesToIndex(
|
|||||||
return interpolateEnvironmentVariables(contents, environmentVariables as any);
|
return interpolateEnvironmentVariables(contents, environmentVariables as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
const NX_PREFIX = /^NX_/i;
|
const NX_PREFIX = /^NX_PUBLIC_/i;
|
||||||
|
|
||||||
// Prevent sensitive keys from being bundled when source code uses entire `process.env` object rather than individual keys (e.g. `process.env.NX_FOO`).
|
|
||||||
// TODO(v19): Only env vars prefixed with NX_PUBLIC should be bundled. This is a breaking change so we won't do it in v18.
|
|
||||||
const excludedKeys = ['NX_CLOUD_ACCESS_TOKEN', 'NX_CLOUD_ENCRYPTION_KEY'];
|
|
||||||
|
|
||||||
function isNxEnvironmentKey(x: string): boolean {
|
function isNxEnvironmentKey(x: string): boolean {
|
||||||
return !excludedKeys.includes(x) && NX_PREFIX.test(x);
|
return NX_PREFIX.test(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getClientEnvironment(deployUrl: string) {
|
function getClientEnvironment(deployUrl: string) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user