Skip to content

Commit

Permalink
feat(vue): add vue preset to create-nx-workspace
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed Sep 12, 2023
1 parent 2d1c990 commit 94b38fa
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 6 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", "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
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';
style: string;
// nextAppDir: boolean;
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) {
preset = parsedArgs.preset;
if (preset === Preset.VueStandalone || preset === Preset.VueMonorepo) {
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
13 changes: 13 additions & 0 deletions packages/workspace/src/generators/new/generate-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,19 @@ function getPresetDependencies({
case Preset.NextJsStandalone:
return { dependencies: { '@nx/next': nxVersion }, dev: {} };

case Preset.VueMonorepo:
case Preset.VueStandalone:
return {
dependencies: {},
dev: {
'@nx/vue': nxVersion,
'@nx/cypress': e2eTestRunner === 'cypress' ? nxVersion : undefined,
'@nx/playwright':
e2eTestRunner === 'playwright' ? nxVersion : undefined,
'@nx/vite': nxVersion,
},
};

case Preset.ReactMonorepo:
case Preset.ReactStandalone:
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ describe('@nx/workspace:generateWorkspaceFiles', () => {
[
Preset.ReactMonorepo,
Preset.ReactStandalone,
Preset.VueMonorepo,
Preset.VueStandalone,
Preset.AngularMonorepo,
Preset.AngularStandalone,
Preset.Nest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ function createAppsAndLibsFolders(tree: Tree, options: NormalizedSchema) {
} else if (
options.preset === Preset.AngularStandalone ||
options.preset === Preset.ReactStandalone ||
options.preset === Preset.VueStandalone ||
options.preset === Preset.NodeStandalone ||
options.preset === Preset.NextJsStandalone ||
options.preset === Preset.TsStandalone ||
Expand Down Expand Up @@ -127,6 +128,7 @@ function createFiles(tree: Tree, options: NormalizedSchema) {
const filesDirName =
options.preset === Preset.AngularStandalone ||
options.preset === Preset.ReactStandalone ||
options.preset === Preset.VueStandalone ||
options.preset === Preset.NodeStandalone ||
options.preset === Preset.NextJsStandalone ||
options.preset === Preset.TsStandalone
Expand Down Expand Up @@ -181,6 +183,7 @@ function addNpmScripts(tree: Tree, options: NormalizedSchema) {
if (
options.preset === Preset.AngularStandalone ||
options.preset === Preset.ReactStandalone ||
options.preset === Preset.VueStandalone ||
options.preset === Preset.NodeStandalone ||
options.preset === Preset.NextJsStandalone
) {
Expand Down
19 changes: 19 additions & 0 deletions packages/workspace/src/generators/new/new.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,25 @@ describe('new', () => {
});
});

it('should generate necessary npm dependencies for vue preset', async () => {
await newGenerator(tree, {
...defaultOptions,
name: 'my-workspace',
directory: 'my-workspace',
appName: 'app',
preset: Preset.VueMonorepo,
});

const { devDependencies } = readJson(tree, 'my-workspace/package.json');
expect(devDependencies).toStrictEqual({
'@nx/vue': nxVersion,
'@nx/cypress': nxVersion,
'@nx/vite': nxVersion,
'@nx/workspace': nxVersion,
nx: nxVersion,
});
});

it('should generate necessary npm dependencies for angular preset', async () => {
await newGenerator(tree, {
...defaultOptions,
Expand Down
24 changes: 24 additions & 0 deletions packages/workspace/src/generators/preset/preset.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ describe('preset', () => {
expect(readProjectConfiguration(tree, 'proj').targets.serve).toBeDefined();
});

it(`should create files (preset = ${Preset.VueMonorepo})`, async () => {
await presetGenerator(tree, {
name: 'proj',
preset: Preset.VueMonorepo,
style: 'css',
linter: 'eslint',
});
expect(tree.exists('apps/proj/src/main.ts')).toBe(true);
expect(readProjectConfiguration(tree, 'proj').targets.serve).toBeDefined();
});

it(`should create files (preset = ${Preset.NextJs})`, async () => {
await presetGenerator(tree, {
name: 'proj',
Expand Down Expand Up @@ -99,4 +110,17 @@ describe('preset', () => {
readProjectConfiguration(tree, 'proj').targets.serve
).toMatchSnapshot();
});

it(`should create files (preset = ${Preset.VueStandalone})`, async () => {
await presetGenerator(tree, {
name: 'proj',
preset: Preset.VueStandalone,
style: 'css',
e2eTestRunner: 'cypress',
});
expect(tree.exists('vite.config.ts')).toBe(true);
expect(
readProjectConfiguration(tree, 'proj').targets.serve
).toMatchSnapshot();
});
});
26 changes: 26 additions & 0 deletions packages/workspace/src/generators/preset/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,32 @@ async function createPreset(tree: Tree, options: Schema) {
e2eTestRunner: options.e2eTestRunner ?? 'cypress',
unitTestRunner: options.bundler === 'vite' ? 'vitest' : 'jest',
});
} else if (options.preset === Preset.VueMonorepo) {
const { applicationGenerator: vueApplicationGenerator } = require('@nx' +
'/vue');

return vueApplicationGenerator(tree, {
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
style: options.style,
linter: options.linter,
e2eTestRunner: options.e2eTestRunner ?? 'cypress',
});
} else if (options.preset === Preset.VueStandalone) {
const { applicationGenerator: vueApplicationGenerator } = require('@nx' +
'/vue');

return vueApplicationGenerator(tree, {
name: options.name,
directory: '.',
projectNameAndRootFormat: 'as-provided',
style: options.style,
linter: options.linter,
rootProject: true,
e2eTestRunner: options.e2eTestRunner ?? 'cypress',
unitTestRunner: 'vitest',
});
} else if (options.preset === Preset.NextJs) {
const { applicationGenerator: nextApplicationGenerator } = require('@nx' +
'/next');
Expand Down
2 changes: 2 additions & 0 deletions packages/workspace/src/generators/utils/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export enum Preset {
AngularStandalone = 'angular-standalone',
ReactMonorepo = 'react-monorepo',
ReactStandalone = 'react-standalone',
VueMonorepo = 'vue-monorepo',
VueStandalone = 'vue-standalone',
NextJsStandalone = 'nextjs-standalone',
ReactNative = 'react-native',
Expo = 'expo',
Expand Down

0 comments on commit 94b38fa

Please sign in to comment.