Skip to content

Commit

Permalink
feat(vue): init, app, component and lib generators (#19130)
Browse files Browse the repository at this point in the history
Co-authored-by: Katerina Skroumpelou <[email protected]>
  • Loading branch information
jaysoo and mandarini authored Sep 13, 2023
1 parent 6a84719 commit 769974b
Show file tree
Hide file tree
Showing 98 changed files with 5,388 additions and 405 deletions.
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", "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", "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 @@ -2084,6 +2084,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 @@ -90,6 +90,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}`
);
});
});
32 changes: 32 additions & 0 deletions e2e/workspace-create/src/create-nx-workspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,38 @@ describe('create-nx-workspace', () => {
}, 90000);
}
});

it('should create a workspace with a single vue app at the root', () => {
const wsName = uniq('vue');

runCreateWorkspace(wsName, {
preset: 'vue-standalone',
appName: wsName,
style: 'css',
packageManager,
e2eTestRunner: 'none',
});

checkFilesExist('package.json');
checkFilesExist('project.json');
checkFilesExist('index.html');
checkFilesExist('src/main.ts');
checkFilesExist('src/App.vue');
expectCodeIsFormatted();
});

it('should be able to create an vue monorepo', () => {
const wsName = uniq('vue');
const appName = uniq('app');
runCreateWorkspace(wsName, {
preset: 'vue-monorepo',
appName,
style: 'css',
packageManager,
e2eTestRunner: 'none',
});
expectCodeIsFormatted();
});
});

describe('create-nx-workspace parent folder', () => {
Expand Down
91 changes: 87 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,15 @@ interface AngularArguments extends BaseArguments {
e2eTestRunner: 'none' | 'cypress' | 'playwright';
}

interface VueArguments extends BaseArguments {
stack: 'vue';
workspaceType: 'standalone' | 'integrated';
appName: string;
// framework: 'none' | 'nuxt';
style: string;
e2eTestRunner: 'none' | 'cypress' | 'playwright';
}

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

Expand Down Expand Up @@ -347,7 +357,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 +370,9 @@ async function determineStack(
case Preset.NextJs:
case Preset.NextJsStandalone:
return 'react';

case Preset.VueStandalone:
case Preset.VueMonorepo:
return 'vue';
case Preset.Nest:
case Preset.NodeStandalone:
case Preset.Express:
Expand All @@ -379,7 +391,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 +406,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 +435,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 +607,69 @@ 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) {
preset = parsedArgs.preset;
} else {
const workspaceType = await determineStandaloneOrMonorepo();

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

if (preset === Preset.VueStandalone) {
appName = parsedArgs.appName ?? parsedArgs.name;
} else {
appName = await determineAppName(parsedArgs);
}

e2eTestRunner = await determineE2eTestRunner(parsedArgs);

if (parsedArgs.style) {
style = parsedArgs.style;
} else {
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 +928,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
2 changes: 2 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 Down
Loading

1 comment on commit 769974b

@vercel
Copy link

@vercel vercel bot commented on 769974b Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-five.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx-dev-nrwl.vercel.app
nx.dev

Please sign in to comment.