fix(nuxt): Add e2e-ci and serve-static targets (#22056)

This commit is contained in:
Nicholas Cunningham 2024-02-28 13:53:20 -07:00 committed by GitHub
parent f046c52e5c
commit 287a0e0616
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 188 additions and 3 deletions

View File

@ -56,7 +56,9 @@ The `@nx/nuxt/plugin` is configured in the `plugins` array in `nx.json`.
"options": { "options": {
"buildTargetName": "build", "buildTargetName": "build",
"testTargetName": "test", "testTargetName": "test",
"serveTargetName": "serve" "serveTargetName": "serve",
"buildStaticTargetName": "build-static",
"serveStaticTargetName": "serve-static"
} }
} }
] ]
@ -65,6 +67,8 @@ The `@nx/nuxt/plugin` is configured in the `plugins` array in `nx.json`.
The `buildTargetName`, `testTargetName` and `serveTargetName` options control the names of the inferred Nuxt tasks. The default names are `build`, `test` and `serve`. The `buildTargetName`, `testTargetName` and `serveTargetName` options control the names of the inferred Nuxt tasks. The default names are `build`, `test` and `serve`.
The `buildStaticTargetName` and `serveStaticTargetName` options control the names of the inferred Nuxt static tasks. The default names are `build-static` and `serve-static`.
## Using Nuxt ## Using Nuxt
### Generate a new Nuxt app ### Generate a new Nuxt app
@ -78,3 +82,23 @@ nx g @nx/nuxt:app my-app
Once you are ready to deploy your Nuxt application, you have absolute freedom to choose any hosting provider that fits your needs. Once you are ready to deploy your Nuxt application, you have absolute freedom to choose any hosting provider that fits your needs.
We have detailed [how to deploy your Nuxt application to Vercel in a separate guide](/recipes/nuxt/deploy-nuxt-to-vercel). We have detailed [how to deploy your Nuxt application to Vercel in a separate guide](/recipes/nuxt/deploy-nuxt-to-vercel).
### E2E testing
By default `nuxt` **does not** generate static HTML files when you run the `build` command. However, Nx provides a `build-static` target that you can use to generate static HTML files for your Nuxt application. Essentially, this target runs the `nuxt build --prerender` command to generate static HTML files.
To perform end-to-end (E2E) testing on static HTML files using a test runner like Cypress. When you create a Nuxt application, Nx automatically creates a `serve-static` target. This target is designed to serve the static HTML files produced by the `build-static` command.
This feature is particularly useful for testing in continuous integration (CI) pipelines, where resources may be constrained. Unlike the `serve` target, `serve-static` does not require a Nuxt's Nitro server to operate, making it more efficient and faster by eliminating background processes, such as file change monitoring.
To utilize the `serve-static` target for testing, run the following command:
```shell
nx serve-static my-nuxt-app-e2e
```
This command performs several actions:
1. It will build the Nuxt application and generate the static HTML files.
2. It will serve the static HTML files using a simple HTTP server.
3. It will run the Cypress tests against the served static HTML files.

View File

@ -56,7 +56,9 @@ The `@nx/nuxt/plugin` is configured in the `plugins` array in `nx.json`.
"options": { "options": {
"buildTargetName": "build", "buildTargetName": "build",
"testTargetName": "test", "testTargetName": "test",
"serveTargetName": "serve" "serveTargetName": "serve",
"buildStaticTargetName": "build-static",
"serveStaticTargetName": "serve-static"
} }
} }
] ]
@ -65,6 +67,8 @@ The `@nx/nuxt/plugin` is configured in the `plugins` array in `nx.json`.
The `buildTargetName`, `testTargetName` and `serveTargetName` options control the names of the inferred Nuxt tasks. The default names are `build`, `test` and `serve`. The `buildTargetName`, `testTargetName` and `serveTargetName` options control the names of the inferred Nuxt tasks. The default names are `build`, `test` and `serve`.
The `buildStaticTargetName` and `serveStaticTargetName` options control the names of the inferred Nuxt static tasks. The default names are `build-static` and `serve-static`.
## Using Nuxt ## Using Nuxt
### Generate a new Nuxt app ### Generate a new Nuxt app
@ -78,3 +82,23 @@ nx g @nx/nuxt:app my-app
Once you are ready to deploy your Nuxt application, you have absolute freedom to choose any hosting provider that fits your needs. Once you are ready to deploy your Nuxt application, you have absolute freedom to choose any hosting provider that fits your needs.
We have detailed [how to deploy your Nuxt application to Vercel in a separate guide](/recipes/nuxt/deploy-nuxt-to-vercel). We have detailed [how to deploy your Nuxt application to Vercel in a separate guide](/recipes/nuxt/deploy-nuxt-to-vercel).
### E2E testing
By default `nuxt` **does not** generate static HTML files when you run the `build` command. However, Nx provides a `build-static` target that you can use to generate static HTML files for your Nuxt application. Essentially, this target runs the `nuxt build --prerender` command to generate static HTML files.
To perform end-to-end (E2E) testing on static HTML files using a test runner like Cypress. When you create a Nuxt application, Nx automatically creates a `serve-static` target. This target is designed to serve the static HTML files produced by the `build-static` command.
This feature is particularly useful for testing in continuous integration (CI) pipelines, where resources may be constrained. Unlike the `serve` target, `serve-static` does not require a Nuxt's Nitro server to operate, making it more efficient and faster by eliminating background processes, such as file change monitoring.
To utilize the `serve-static` target for testing, run the following command:
```shell
nx serve-static my-nuxt-app-e2e
```
This command performs several actions:
1. It will build the Nuxt application and generate the static HTML files.
2. It will serve the static HTML files using a simple HTTP server.
3. It will run the Cypress tests against the served static HTML files.

View File

@ -3,6 +3,7 @@ import {
cleanupProject, cleanupProject,
killPorts, killPorts,
newProject, newProject,
readJson,
runCLI, runCLI,
uniq, uniq,
} from '@nx/e2e/utils'; } from '@nx/e2e/utils';
@ -16,7 +17,7 @@ describe('Nuxt Plugin', () => {
unsetProjectNameAndRootFormat: false, unsetProjectNameAndRootFormat: false,
}); });
runCLI( runCLI(
`generate @nx/nuxt:app ${app} --unitTestRunner=vitest --projectNameAndRootFormat=as-provided` `generate @nx/nuxt:app ${app} --unitTestRunner=vitest --projectNameAndRootFormat=as-provided e2eTestRunner=cypress`
); );
runCLI( runCLI(
`generate @nx/nuxt:component --directory=${app}/src/components/one --name=one --nameAndDirectoryFormat=as-provided --unitTestRunner=vitest` `generate @nx/nuxt:component --directory=${app}/src/components/one --name=one --nameAndDirectoryFormat=as-provided --unitTestRunner=vitest`
@ -54,4 +55,14 @@ describe('Nuxt Plugin', () => {
runCLI(`run ${app}:build-storybook --verbose`); runCLI(`run ${app}:build-storybook --verbose`);
checkFilesExist(`${app}/storybook-static/index.html`); checkFilesExist(`${app}/storybook-static/index.html`);
}, 300_000); }, 300_000);
it('should have build, serve, build-static, server-static targets', () => {
runCLI(`show project ${app} --json > targets.json`);
const targets = readJson('targets.json');
expect(targets.targets['build']).toBeDefined();
expect(targets.targets['serve']).toBeDefined();
expect(targets.targets['serve-static']).toBeDefined();
expect(targets.targets['build-static']).toBeDefined();
});
}); });

View File

@ -22,6 +22,8 @@ describe('app', () => {
expect(projectConfig.targets.build).toBeUndefined(); expect(projectConfig.targets.build).toBeUndefined();
expect(projectConfig.targets.serve).toBeUndefined(); expect(projectConfig.targets.serve).toBeUndefined();
expect(projectConfig.targets.test).toBeUndefined(); expect(projectConfig.targets.test).toBeUndefined();
expect(projectConfig.targets['build-static']).toBeUndefined();
expect(projectConfig.targets['serve-static']).toBeUndefined();
}); });
it('should create all new files in the correct location', async () => { it('should create all new files in the correct location', async () => {

View File

@ -28,6 +28,12 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
bundler: 'vite', bundler: 'vite',
skipFormat: true, skipFormat: true,
devServerTarget: `${options.projectName}:serve`, devServerTarget: `${options.projectName}:serve`,
webServerCommands: {
default: `${getPackageManagerCommand().exec} nx serve ${
options.projectName
}`,
},
ciWebServerCommand: `nx run ${options.projectName}:serve-static`,
baseUrl: 'http://localhost:4200', baseUrl: 'http://localhost:4200',
jsx: true, jsx: true,
addPlugin: true, addPlugin: true,

View File

@ -67,6 +67,7 @@ export function addPlugin(tree: Tree) {
options: { options: {
buildTargetName: 'build', buildTargetName: 'build',
serveTargetName: 'serve', serveTargetName: 'serve',
serveStaticTargetName: 'serve-static',
}, },
}); });
} }

View File

@ -6,6 +6,36 @@ exports[`@nx/nuxt/plugin not root project should create nodes 1`] = `
"my-app": { "my-app": {
"root": "my-app", "root": "my-app",
"targets": { "targets": {
"acme-build-static": {
"cache": true,
"command": "nuxt build --prerender",
"dependsOn": [
"^acme-build-static",
],
"inputs": [
"production",
"^production",
{
"externalDependencies": [
"nuxt",
],
},
],
"options": {
"cwd": "my-app",
},
"outputs": [
"{workspaceRoot}/dist/my-app/",
],
},
"acme-serve-static": {
"executor": "@nx/web:file-server",
"options": {
"buildTarget": "acme-build-static",
"port": 4200,
"staticFilePath": "{projectRoot}/dist",
},
},
"build-something": { "build-something": {
"cache": true, "cache": true,
"command": "nuxt build", "command": "nuxt build",
@ -68,12 +98,42 @@ exports[`@nx/nuxt/plugin root project should create nodes 1`] = `
"dist/my-app/", "dist/my-app/",
], ],
}, },
"build-static": {
"cache": true,
"command": "nuxt build --prerender",
"dependsOn": [
"^build-static",
],
"inputs": [
"production",
"^production",
{
"externalDependencies": [
"nuxt",
],
},
],
"options": {
"cwd": ".",
},
"outputs": [
"dist/my-app/",
],
},
"serve": { "serve": {
"command": "nuxt dev", "command": "nuxt dev",
"options": { "options": {
"cwd": ".", "cwd": ".",
}, },
}, },
"serve-static": {
"executor": "@nx/web:file-server",
"options": {
"buildTarget": "build-static",
"port": 4200,
"staticFilePath": "{projectRoot}/dist",
},
},
}, },
}, },
}, },

View File

@ -51,6 +51,8 @@ describe('@nx/nuxt/plugin', () => {
{ {
buildTargetName: 'build', buildTargetName: 'build',
serveTargetName: 'serve', serveTargetName: 'serve',
buildStaticTargetName: 'build-static',
serveStaticTargetName: 'serve-static',
}, },
context context
); );
@ -89,6 +91,8 @@ describe('@nx/nuxt/plugin', () => {
{ {
buildTargetName: 'build-something', buildTargetName: 'build-something',
serveTargetName: 'my-serve', serveTargetName: 'my-serve',
buildStaticTargetName: 'acme-build-static',
serveStaticTargetName: 'acme-serve-static',
}, },
context context
); );

View File

@ -46,6 +46,8 @@ export const createDependencies: CreateDependencies = () => {
export interface NuxtPluginOptions { export interface NuxtPluginOptions {
buildTargetName?: string; buildTargetName?: string;
serveTargetName?: string; serveTargetName?: string;
serveStaticTargetName?: string;
buildStaticTargetName?: string;
} }
export const createNodes: CreateNodes<NuxtPluginOptions> = [ export const createNodes: CreateNodes<NuxtPluginOptions> = [
@ -108,6 +110,15 @@ async function buildNuxtTargets(
targets[options.serveTargetName] = serveTarget(projectRoot); targets[options.serveTargetName] = serveTarget(projectRoot);
targets[options.serveStaticTargetName] = serveStaticTarget(options);
targets[options.buildStaticTargetName] = buildStaticTarget(
options.buildStaticTargetName,
namedInputs,
buildOutputs,
projectRoot
);
return targets; return targets;
} }
@ -148,6 +159,46 @@ function serveTarget(projectRoot: string) {
return targetConfig; return targetConfig;
} }
function serveStaticTarget(options: NuxtPluginOptions) {
const targetConfig: TargetConfiguration = {
executor: '@nx/web:file-server',
options: {
buildTarget: `${options.buildStaticTargetName}`,
staticFilePath: '{projectRoot}/dist',
port: 4200,
},
};
return targetConfig;
}
function buildStaticTarget(
buildStaticTargetName: string,
namedInputs: {
[inputName: string]: any[];
},
buildOutputs: string[],
projectRoot: string
) {
const targetConfig: TargetConfiguration = {
command: `nuxt build --prerender`,
options: { cwd: projectRoot },
cache: true,
dependsOn: [`^${buildStaticTargetName}`],
inputs: [
...('production' in namedInputs
? ['production', '^production']
: ['default', '^default']),
{
externalDependencies: ['nuxt'],
},
],
outputs: buildOutputs,
};
return targetConfig;
}
async function getInfoFromNuxtConfig( async function getInfoFromNuxtConfig(
configFilePath: string, configFilePath: string,
context: CreateNodesContext, context: CreateNodesContext,
@ -216,5 +267,7 @@ function normalizeOptions(options: NuxtPluginOptions): NuxtPluginOptions {
options ??= {}; options ??= {};
options.buildTargetName ??= 'build'; options.buildTargetName ??= 'build';
options.serveTargetName ??= 'serve'; options.serveTargetName ??= 'serve';
options.serveStaticTargetName ??= 'serve-static';
options.buildStaticTargetName ??= 'build-static';
return options; return options;
} }