Skip to content

Commit

Permalink
feat(vite): allow user to set their custom target for transform (#13691)
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed Dec 16, 2022
1 parent 578ecb6 commit b52b649
Show file tree
Hide file tree
Showing 18 changed files with 1,148 additions and 159 deletions.
19 changes: 18 additions & 1 deletion docs/generated/packages/vite.json
Expand Up @@ -63,7 +63,7 @@
"$default": { "$source": "argv", "index": 0 },
"aliases": ["name", "projectName"],
"x-dropdown": "project",
"x-prompt": "What is the name of the project to set up a webpack for?"
"x-prompt": "What is the name of the project to set up Vite for?"
},
"includeLib": {
"type": "boolean",
Expand All @@ -82,6 +82,18 @@
"description": "Is this a new project?",
"default": false,
"hidden": true
},
"buildTarget": {
"type": "string",
"description": "The build target of the project to be transformed to use the @nrwl/vite:build executor."
},
"serveTarget": {
"type": "string",
"description": "The serve target of the project to be transformed to use the @nrwl/vite:dev-server executor."
},
"testTarget": {
"type": "string",
"description": "The test target of the project to be transformed to use the @nrwl/vite:test executor."
}
},
"examplesFile": "This is a generator for setting up Vite configuration for an existing React or Web application. It will change the build and serve targets to use the `@nrwl/vite` executors for serving and building the application. This generator will modify your code, so make sure to commit your changes before running it.\n\n```bash\nnx g @nrwl/vite:configuration\n```\n\nWhen running this generator, you will be prompted to provide the following:\n\n- The `project`, as the name of the project you want to generate the configuration for.\n- The `uiFramework` you want to use. Supported values are: `react` and `none`.\n\nYou must provide a `project` and a `uiFramework` for the generator to work.\n\nYou can read more about how this generator works, in the [Vite package overview page](/packages/vite).\n\n## Examples\n\n### Change a React app to use Vite\n\n```bash\nnx g @nrwl/vite:configuration --project=my-app --uiFramework=react\n```\n\nThis will change the `my-app` project to use Vite instead of the default Webpack configuration. The changes this generator will do are described in the [Vite package overview page](/packages/vite).\n\n### Change a Web app to use Vite\n\n```bash\nnx g @nrwl/vite:configuration --project=my-app --uiFramework=none\n```\n\nThis will change the `my-app` project to use Vite instead of the existing bundler configuration.\n",
Expand Down Expand Up @@ -130,6 +142,11 @@
"enum": ["c8", "istanbul"],
"default": "c8",
"description": "Coverage provider to use."
},
"testTarget": {
"type": "string",
"description": "The test target of the project to be transformed to use the @nrwl/vite:test executor.",
"hidden": true
}
},
"required": ["project"],
Expand Down
2 changes: 1 addition & 1 deletion e2e/react/src/react-package.test.ts
Expand Up @@ -377,7 +377,7 @@ describe('Build React applications and libraries with Vite', () => {
// Convert non-buildable lib to buildable one
const nonBuildableLib = uniq('nonbuildablelib');
runCLI(
`generate @nrwl/react:lib ${nonBuildableLib} --no-interactive --unitTestRunner=none`
`generate @nrwl/react:lib ${nonBuildableLib} --no-interactive --unitTestRunner=jest`
);
runCLI(
`generate @nrwl/vite:configuration ${nonBuildableLib} --uiFramework=react --no-interactive`
Expand Down
3 changes: 2 additions & 1 deletion packages/vite/package.json
Expand Up @@ -34,7 +34,8 @@
"@nrwl/js": "file:../js",
"@swc/helpers": "^0.4.11",
"chalk": "4.1.0",
"dotenv": "~10.0.0"
"dotenv": "~10.0.0",
"enquirer": "~2.3.6"
},
"peerDependencies": {
"vite": "^4.0.1",
Expand Down
@@ -1,5 +1,75 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`@nrwl/vite:configuration transform React app to use Vite by providing custom targets transform React app if supported executor is provided should transform workspace.json project config 1`] = `
"{
\\"projects\\": {
\\"my-test-mixed-react-app\\": {
\\"$schema\\": \\"../../node_modules/nx/schemas/project-schema.json\\",
\\"root\\": \\"apps/my-test-mixed-react-app\\",
\\"sourceRoot\\": \\"apps/my-test-mixed-react-app/src\\",
\\"projectType\\": \\"application\\",
\\"architect\\": {
\\"invalid-build\\": {
\\"builder\\": \\"@nrwl/js:tsc\\",
\\"outputs\\": [
\\"{options.outputPath}\\"
]
},
\\"valid-build\\": {
\\"builder\\": \\"@nrwl/vite:build\\",
\\"outputs\\": [
\\"{options.outputPath}\\"
],
\\"options\\": {
\\"outputPath\\": \\"dist/apps/my-test-mixed-react-app\\"
}
},
\\"serve\\": {
\\"builder\\": \\"@nrwl/vite:dev-server\\",
\\"defaultConfiguration\\": \\"development\\",
\\"options\\": {
\\"buildTarget\\": \\"my-test-mixed-react-app:build\\"
},
\\"configurations\\": {
\\"development\\": {
\\"buildTarget\\": \\"my-test-mixed-react-app:build:development\\"
},
\\"production\\": {
\\"buildTarget\\": \\"my-test-mixed-react-app:build:production\\",
\\"hmr\\": false
}
}
},
\\"lint\\": {
\\"builder\\": \\"@nrwl/linter:eslint\\",
\\"outputs\\": [
\\"{options.outputFile}\\"
],
\\"options\\": {
\\"lintFilePatterns\\": [
\\"apps/my-test-mixed-react-app/**/*.{ts,tsx,js,jsx}\\"
]
}
},
\\"test\\": {
\\"builder\\": \\"@nrwl/jest:jest\\",
\\"outputs\\": [
\\"{workspaceRoot}/coverage/{projectRoot}\\"
],
\\"options\\": {
\\"jestConfig\\": \\"apps/my-test-mixed-react-app/jest.config.ts\\",
\\"passWithNoTests\\": true
}
}
},
\\"tags\\": []
}
},
\\"version\\": 1
}
"
`;

exports[`@nrwl/vite:configuration transform React app to use Vite should transform workspace.json project config 1`] = `
"{
\\"projects\\": {
Expand Down
166 changes: 164 additions & 2 deletions packages/vite/src/generators/configuration/configuration.spec.ts
Expand Up @@ -9,7 +9,10 @@ import { nxVersion } from '../../utils/versions';

import { viteConfigurationGenerator } from './configuration';
import {
mockAngularAppGenerator,
mockReactAppGenerator,
mockReactMixedAppGenerator,
mockUnknownAppGenerator,
mockWebAppGenerator,
} from '../../utils/test-utils';

Expand All @@ -19,7 +22,7 @@ describe('@nrwl/vite:configuration', () => {
describe('transform React app to use Vite', () => {
beforeAll(async () => {
tree = createTreeWithEmptyV1Workspace();
await mockReactAppGenerator(tree);
mockReactAppGenerator(tree);
const existing = 'existing';
const existingVersion = '1.0.0';
addDependenciesToPackageJson(
Expand Down Expand Up @@ -65,7 +68,7 @@ describe('@nrwl/vite:configuration', () => {
describe('transform Web app to use Vite', () => {
beforeAll(async () => {
tree = createTreeWithEmptyV1Workspace();
await mockWebAppGenerator(tree);
mockWebAppGenerator(tree);
const existing = 'existing';
const existingVersion = '1.0.0';
addDependenciesToPackageJson(
Expand Down Expand Up @@ -105,6 +108,165 @@ describe('@nrwl/vite:configuration', () => {
});
});

describe('do not transform Angular app to use Vite', () => {
beforeAll(async () => {
tree = createTreeWithEmptyV1Workspace();
mockAngularAppGenerator(tree);
});
it('should throw when trying to convert', async () => {
expect.assertions(2);

try {
await viteConfigurationGenerator(tree, {
uiFramework: 'none',
project: 'my-test-angular-app',
});
} catch (e) {
expect(e).toBeDefined();
expect(e.toString()).toContain(
'The project my-test-angular-app cannot be converted to use the @nrwl/vite executors'
);
}
});
});

describe('inform user of unknown targets when converting', () => {
beforeAll(async () => {
tree = createTreeWithEmptyV1Workspace();
mockUnknownAppGenerator(tree);
});

it('should throw when trying to convert something unknown', async () => {
const { Confirm } = require('enquirer');
const confirmSpy = jest.spyOn(Confirm.prototype, 'run');
confirmSpy.mockResolvedValue(true);
expect.assertions(2);

try {
await viteConfigurationGenerator(tree, {
uiFramework: 'none',
project: 'my-test-random-app',
});
} catch (e) {
expect(e).toBeDefined();
expect(e.toString()).toContain(
'Error: Cannot find apps/my-test-random-app/tsconfig.json'
);
}
});

it('should throw when trying to convert something unknown and user denies conversion', async () => {
const { Confirm } = require('enquirer');
const confirmSpy = jest.spyOn(Confirm.prototype, 'run');
confirmSpy.mockResolvedValue(false);

expect.assertions(2);

try {
await viteConfigurationGenerator(tree, {
uiFramework: 'none',
project: 'my-test-random-app',
});
} catch (e) {
expect(e).toBeDefined();
expect(e.toString()).toContain(
'Nx could not verify that the executors you are using can be converted to the @nrwl/vite executors.'
);
}
});
});

describe('transform React app to use Vite by providing custom targets', () => {
describe('transform React app if supported executor is provided', () => {
beforeEach(async () => {
tree = createTreeWithEmptyV1Workspace();
mockReactMixedAppGenerator(tree);
const existing = 'existing';
const existingVersion = '1.0.0';
addDependenciesToPackageJson(
tree,
{ '@nrwl/vite': nxVersion, [existing]: existingVersion },
{ [existing]: existingVersion }
);
await viteConfigurationGenerator(tree, {
uiFramework: 'react',
project: 'my-test-mixed-react-app',
buildTarget: 'valid-build',
});
});
it('should add vite packages and react-related dependencies for vite', async () => {
const packageJson = readJson(tree, '/package.json');
expect(packageJson.devDependencies).toMatchObject({
vite: expect.any(String),
'@vitejs/plugin-react': expect.any(String),
});
});

it('should create vite.config file at the root of the app', () => {
expect(tree.exists('apps/my-test-mixed-react-app/vite.config.ts')).toBe(
true
);
});

it('should transform workspace.json project config', () => {
expect(tree.read('workspace.json', 'utf-8')).toMatchSnapshot();
});
});

describe('do NOT transform React app if unsupported executor is provided', () => {
beforeEach(async () => {
tree = createTreeWithEmptyV1Workspace();
mockReactMixedAppGenerator(tree);
const existing = 'existing';
const existingVersion = '1.0.0';
addDependenciesToPackageJson(
tree,
{ '@nrwl/vite': nxVersion, [existing]: existingVersion },
{ [existing]: existingVersion }
);
});
it('should throw when trying to convert and user denies', async () => {
const { Confirm } = require('enquirer');
const confirmSpy = jest.spyOn(Confirm.prototype, 'run');
confirmSpy.mockResolvedValue(false);
expect.assertions(2);

try {
await viteConfigurationGenerator(tree, {
uiFramework: 'none',
project: 'my-test-mixed-react-app',
buildTarget: 'invalid-build',
});
} catch (e) {
expect(e).toBeDefined();
expect(e.toString()).toContain(
'The build target invalid-build cannot be converted to use the @nrwl/vite:build executor'
);
}
});

it('should NOT throw error when trying to convert and user confirms', async () => {
const { Confirm } = require('enquirer');
const confirmSpy = jest.spyOn(Confirm.prototype, 'run');
confirmSpy.mockResolvedValue(true);
expect.assertions(1);

try {
await viteConfigurationGenerator(tree, {
uiFramework: 'none',
project: 'my-test-mixed-react-app',
buildTarget: 'invalid-build',
});
expect(
tree.exists('apps/my-test-mixed-react-app/vite.config.ts')
).toBe(true);
} catch (e) {
throw new Error('Should not throw error');
}
});
});
});

describe('vitest', () => {
beforeAll(async () => {
tree = createTreeWithEmptyV1Workspace();
Expand Down

1 comment on commit b52b649

@vercel
Copy link

@vercel vercel bot commented on b52b649 Dec 16, 2022

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-dev-git-master-nrwl.vercel.app
nx-five.vercel.app
nx-dev-nrwl.vercel.app
nx.dev

Please sign in to comment.