Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vue): init, app, component and lib generators #19130

Merged
merged 4 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ tmp
jest.debug.config.js
.tool-versions
/.nx-cache
/.nx
/.verdaccio/build/local-registry
/graph/client/src/assets/environment.js
/graph/client/src/assets/dev/environment.js
Expand Down
2 changes: 1 addition & 1 deletion docs/generated/cli/create-nx-workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Package manager to use

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", "next", "nextjs-standalone", "react-native", "expo", "nest", "express", "react", "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", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "next", "nextjs-standalone", "react-native", "expo", "nest", "express", "react", "angular", "vue", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset

### routing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ Package manager to use

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", "next", "nextjs-standalone", "react-native", "expo", "nest", "express", "react", "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", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "next", "nextjs-standalone", "react-native", "expo", "nest", "express", "react", "angular", "vue", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset

### routing

Expand Down
14 changes: 14 additions & 0 deletions docs/map.json
Original file line number Diff line number Diff line change
Expand Up @@ -2079,6 +2079,20 @@
}
]
},
{
"name": "vue",
"id": "vue",
"description": "Vue package.",
"itemList": [
{
"id": "overview",
"path": "/packages/vue",
"name": "Overview of the Nx Vue Plugin",
"description": "The Nx Plugin for Vue contains generators for managing Vue applications and libraries within an Nx workspace. This page also explains how to configure Vue on your Nx workspace.",
"file": "shared/packages/vue/vue-plugin"
}
]
},
{
"name": "webpack",
"id": "webpack",
Expand Down
10 changes: 10 additions & 0 deletions docs/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,16 @@
"generators": ["init", "configuration", "vitest"]
}
},
{
"name": "vue",
"packageName": "vue",
"description": "The Vue plugin for Nx contains executors and generators for managing Vue applications and libraries within an Nx workspace. It provides:\n\n\n- Integration with libraries such as Jest, Cypress, and Storybook.\n\n- Generators for applications, libraries, components, hooks, and more.\n\n- Library build support for publishing packages to npm or other registries.\n\n- Utilities for automatic workspace refactoring.",
"path": "generated/packages/vite.json",
"schemas": {
"executors": [],
"generators": ["init", "library", "application", "component"]
}
},
{
"name": "web",
"packageName": "web",
Expand Down
60 changes: 60 additions & 0 deletions docs/shared/packages/vue/vue-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
title: Overview of the Nx Vue Plugin
description: The Nx Plugin for Vue contains generators for managing Vue applications and libraries within an Nx workspace. This page also explains how to configure Vue on your Nx workspace.
---

The Nx plugin for [Vue](https://vuejs.org/).

## Setting up a new Nx workspace with Vue

You can create a new workspace that uses Vue with one of the following commands:

- Generate a new monorepo with a Vue app set up with Vue

```shell
npx create-nx-workspace@latest --preset=vue
```

## Add Vue to an existing workspace

There are a number of ways to use Vue in your existing workspace.

### Install the `@nx/vue` plugin

{% tabs %}
{% tab label="npm" %}

```shell
npm install -D @nx/vue
```

{% /tab %}
{% tab label="yarn" %}

```shell
yarn add -D @nx/vue
```

{% /tab %}
{% tab label="pnpm" %}

```shell
pnpm install -D @nx/vue
```

{% /tab %}
{% /tabs %}

### Generate a new project using Vue

To generate a Vue application, run the following:

```bash
nx g @nx/vue:app my-app
```

To generate a Vue library, run the following:

```bash
nx g @nx/vue:lib my-lib
```
1 change: 1 addition & 0 deletions e2e/utils/create-project-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export function newProject({
`@nx/rollup`,
`@nx/react`,
`@nx/storybook`,
`@nx/vue`,
`@nx/vite`,
`@nx/web`,
`@nx/webpack`,
Expand Down
54 changes: 54 additions & 0 deletions e2e/vue/src/vue.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
cleanupProject,
killPorts,
newProject,
runCLI,
runE2ETests,
uniq,
} from '@nx/e2e/utils';

describe('Vue Plugin', () => {
let proj: string;

beforeAll(() => {
proj = newProject({
unsetProjectNameAndRootFormat: false,
});
});

afterAll(() => cleanupProject());

it('should serve application in dev mode', async () => {
const app = uniq('app');

runCLI(
`generate @nx/vue:app ${app} --unitTestRunner=vitest --e2eTestRunner=playwright`
);
let result = runCLI(`test ${app}`);
expect(result).toContain(`Successfully ran target test for project ${app}`);

result = runCLI(`build ${app}`);
expect(result).toContain(
`Successfully ran target build for project ${app}`
);

if (runE2ETests()) {
const e2eResults = runCLI(`e2e ${app}-e2e --no-watch`);
expect(e2eResults).toContain('Successfully ran target e2e');
expect(await killPorts()).toBeTruthy();
}
}, 200_000);

it('should build library', async () => {
const lib = uniq('lib');

runCLI(
`generate @nx/vue:lib ${lib} --bundler=vite --unitTestRunner=vitest`
);

const result = runCLI(`build ${lib}`);
expect(result).toContain(
`Successfully ran target build for project ${lib}`
);
});
});
98 changes: 94 additions & 4 deletions packages/create-nx-workspace/bin/create-nx-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ interface AngularArguments extends BaseArguments {
e2eTestRunner: 'none' | 'cypress' | 'playwright';
}

interface VueArguments extends BaseArguments {
stack: 'vue';
workspaceType: 'standalone' | 'integrated';
appName: string;
// framework: 'none' | 'nuxt';
mandarini marked this conversation as resolved.
Show resolved Hide resolved
style: string;
// nextAppDir: boolean;
mandarini marked this conversation as resolved.
Show resolved Hide resolved
e2eTestRunner: 'none' | 'cypress' | 'playwright';
}

interface NodeArguments extends BaseArguments {
stack: 'node';
workspaceType: 'standalone' | 'integrated';
Expand All @@ -78,6 +88,7 @@ type Arguments =
| NoneArguments
| ReactArguments
| AngularArguments
| VueArguments
| NodeArguments
| UnknownStackArguments;

Expand Down Expand Up @@ -347,7 +358,7 @@ async function determineFolder(

async function determineStack(
parsedArgs: yargs.Arguments<Arguments>
): Promise<'none' | 'react' | 'angular' | 'node' | 'unknown'> {
): Promise<'none' | 'react' | 'angular' | 'vue' | 'node' | 'unknown'> {
if (parsedArgs.preset) {
switch (parsedArgs.preset) {
case Preset.Angular:
Expand All @@ -360,7 +371,10 @@ async function determineStack(
case Preset.NextJs:
case Preset.NextJsStandalone:
return 'react';

case Preset.Vue:
case Preset.VueStandalone:
case Preset.VueMonorepo:
return 'vue';
case Preset.Nest:
case Preset.NodeStandalone:
case Preset.Express:
Expand All @@ -379,7 +393,7 @@ async function determineStack(
}

const { stack } = await enquirer.prompt<{
stack: 'none' | 'react' | 'angular' | 'node';
stack: 'none' | 'react' | 'angular' | 'node' | 'vue';
}>([
{
name: 'stack',
Expand All @@ -394,6 +408,10 @@ async function determineStack(
name: `react`,
message: `React: Configures a React application with your framework of choice.`,
},
{
name: `vue`,
message: `Vue: Configures a Vue application with modern tooling.`,
},
{
name: `angular`,
message: `Angular: Configures a Angular application with modern tooling.`,
Expand All @@ -419,6 +437,8 @@ async function determinePresetOptions(
return determineReactOptions(parsedArgs);
case 'angular':
return determineAngularOptions(parsedArgs);
case 'vue':
return determineVueOptions(parsedArgs);
case 'node':
return determineNodeOptions(parsedArgs);
default:
Expand Down Expand Up @@ -589,6 +609,74 @@ async function determineReactOptions(
return { preset, style, appName, bundler, nextAppDir, e2eTestRunner };
}

async function determineVueOptions(
parsedArgs: yargs.Arguments<VueArguments>
): Promise<Partial<Arguments>> {
let preset: Preset;
let style: undefined | string = undefined;
let appName: string;
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;

if (parsedArgs.preset && parsedArgs.preset !== Preset.Vue) {
jaysoo marked this conversation as resolved.
Show resolved Hide resolved
preset = parsedArgs.preset;
if (preset === Preset.VueStandalone || preset === Preset.VueMonorepo) {
jaysoo marked this conversation as resolved.
Show resolved Hide resolved
appName = parsedArgs.appName ?? parsedArgs.name;
} else {
appName = await determineAppName(parsedArgs);
}
} else {
const workspaceType = await determineStandaloneOrMonorepo();

if (workspaceType === 'standalone') {
appName = parsedArgs.name;
} else {
appName = await determineAppName(parsedArgs);
}

if (workspaceType === 'standalone') {
preset = Preset.VueStandalone;
} else {
preset = Preset.VueMonorepo;
}
}

e2eTestRunner = await determineE2eTestRunner(parsedArgs);

if (parsedArgs.style) {
style = parsedArgs.style;
} else if (preset === Preset.VueMonorepo || preset === Preset.VueStandalone) {
const reply = await enquirer.prompt<{ style: string }>([
{
name: 'style',
message: `Default stylesheet format`,
initial: 'css' as any,
type: 'autocomplete',
choices: [
{
name: 'css',
message: 'CSS',
},
{
name: 'scss',
message: 'SASS(.scss) [ http://sass-lang.com ]',
},
{
name: 'less',
message: 'LESS [ http://lesscss.org ]',
},
{
name: 'none',
message: 'None',
},
],
},
]);
style = reply.style;
}

return { preset, style, appName, e2eTestRunner };
}

async function determineAngularOptions(
parsedArgs: yargs.Arguments<AngularArguments>
): Promise<Partial<Arguments>> {
Expand Down Expand Up @@ -847,7 +935,9 @@ async function determineStandaloneOrMonorepo(): Promise<
}

async function determineAppName(
parsedArgs: yargs.Arguments<ReactArguments | AngularArguments | NodeArguments>
parsedArgs: yargs.Arguments<
ReactArguments | AngularArguments | NodeArguments | VueArguments
>
): Promise<string> {
if (parsedArgs.appName) return parsedArgs.appName;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export const presetOptions: { name: Preset; message: string }[] = [
name: Preset.AngularMonorepo,
message: 'angular [a monorepo with a single Angular application]',
},
{
name: Preset.VueMonorepo,
message: 'vue [a monorepo with a single Vue application]',
},
{
name: Preset.NextJs,
message: 'next.js [a monorepo with a single Next.js application]',
Expand Down
3 changes: 3 additions & 0 deletions packages/create-nx-workspace/src/utils/preset/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export enum Preset {
AngularStandalone = 'angular-standalone',
ReactMonorepo = 'react-monorepo',
ReactStandalone = 'react-standalone',
VueMonorepo = 'vue-monorepo',
VueStandalone = 'vue-standalone',
NextJs = 'next',
NextJsStandalone = 'nextjs-standalone',
ReactNative = 'react-native',
Expand All @@ -17,6 +19,7 @@ export enum Preset {
Express = 'express',
React = 'react',
Angular = 'angular',
Vue = 'vue',
NodeStandalone = 'node-standalone',
NodeMonorepo = 'node-monorepo',
TsStandalone = 'ts-standalone',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ describe('app', () => {
'vitest/importMeta',
'vite/client',
'node',
'vitest',
]);
});

Expand Down
Loading