diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fc739a..dd40db5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ TODO -- automate changelog generation - Update packages - Update to Nx 18.3.4 - Make Cypress optional peer dependency +- BREAKING - may need to add project path to vitest executors in project.json. For example, `"config": "apps/myproject/vite.config.ts"` +- BREAKING - postcss config may need to be renamed from `postcss.config.js` to `postcss.config.mjs` ### v0.27.0 - 240117 diff --git a/e2e/vue3-vite-e2e/tests/library.spec.ts b/e2e/vue3-vite-e2e/tests/library.spec.ts index e5c6f16..893c4d7 100644 --- a/e2e/vue3-vite-e2e/tests/library.spec.ts +++ b/e2e/vue3-vite-e2e/tests/library.spec.ts @@ -1,3 +1,4 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { checkFilesExist, cleanup, @@ -16,16 +17,16 @@ jest.setTimeout(60000); describe('library e2e', () => { let proj: string; - afterAll(() => { - cleanup(proj); - }); - describe('basic library check', () => { beforeAll(() => { proj = uniq('vue3-vite'); ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); }); + afterAll(() => { + cleanup(proj); + }); + it('should create library and build', async () => { // Create library const library = uniq('library'); @@ -33,7 +34,7 @@ describe('library e2e', () => { // Check files exist checkFilesExist(proj, [ - `libs/${library}/postcss.config.js`, + `libs/${library}/postcss.config.mjs`, `libs/${library}/project.json`, `libs/${library}/vite.config.ts`, `libs/${library}/src/index.ts`, @@ -100,7 +101,7 @@ describe('library e2e', () => { // Lint const lintResult = await runNxCommandAsync(proj, `lint ${library}`); - expect(lintResult.stdout).toContain('All files pass linting.'); + expect(lintResult.stdout).toContain('All files pass linting'); }); it('should add path to `tsconfig.base.json`', async () => { @@ -120,56 +121,67 @@ describe('library e2e', () => { }); }); - it('should not overwrite `dependencies` in `package.json`', async () => { - // Reset project to verify correct dependencies are installed - proj = uniq('vue3-vite'); - ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); - - // Install Vue 2 - const packageName = 'vue'; - const oldVersion = '^2.7.16'; - await runCommandAsync( - proj, - `npm install ${packageName}@${oldVersion} --save`, - ); - - // Verify `dependencies` after install - let packageJson = readJson(proj, 'package.json'); - expect(packageJson.dependencies[packageName]).toEqual(oldVersion); - - // Create library - const library = uniq('library-dep'); - await runNxCommandAsync(proj, `generate nx-vue3-vite:library ${library}`); - - // Verify `dependencies` after running the generator - packageJson = readJson(proj, 'package.json'); - expect(packageJson.dependencies[packageName]).toEqual(oldVersion); - }); + describe('update configuration', () => { + beforeEach(() => { + proj = uniq('vue3-vite'); + ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); + }); + + afterEach(() => { + cleanup(proj); + }); + + it('should not overwrite `dependencies` in `package.json`', async () => { + const pmc = getPackageManagerCommand(); + + // Install Vue 2 + const packageName = 'vue'; + const oldVersion = '^2.7.16'; + await runCommandAsync( + proj, + `${pmc.install} ${packageName}@${oldVersion} --save`, + ); + + // Verify `dependencies` after install + let packageJson = readJson(proj, 'package.json'); + expect(packageJson.dependencies[packageName]).toEqual(oldVersion); + + // Create library + const library = uniq('library-dep'); + await runNxCommandAsync(proj, `generate nx-vue3-vite:library ${library}`); + + // Verify `dependencies` after running the generator + packageJson = readJson(proj, 'package.json'); + expect(packageJson.dependencies[packageName]).toEqual(oldVersion); + }); - it('should not overwrite `devDependencies` in `package.json`', async () => { - // Reset project to verify correct dependencies are installed - proj = uniq('vue3-vite'); - ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); - - // Install Vite 3 - const packageName = 'vite'; - const oldVersion = '^3.2.10'; - await runCommandAsync( - proj, - `npm install ${packageName}@${oldVersion} --save-dev`, - ); - - // Verify `dependencies` after install - let packageJson = readJson(proj, 'package.json'); - expect(packageJson.devDependencies[packageName]).toEqual(oldVersion); - - // Create library - const library = uniq('library-dev-dep'); - await runNxCommandAsync(proj, `generate nx-vue3-vite:library ${library}`); - - // Verify `devDepndencies` after running the generator - packageJson = readJson(proj, 'package.json'); - expect(packageJson.devDependencies[packageName]).toEqual(oldVersion); + it('should not overwrite `devDependencies` in `package.json`', async () => { + const pmc = getPackageManagerCommand(); + + // Install Vite 3 + const packageName = 'vite'; + const oldVersion = '5.2.5'; + await runCommandAsync( + proj, + `${pmc.install} -D ${packageName}@${oldVersion}`, + ); + + // Verify `dependencies` after install + let packageJson = readJson(proj, 'package.json'); + expect(packageJson.devDependencies[packageName]).toEqual( + `^${oldVersion}`, + ); + + // Create library + const library = uniq('library-dev-dep'); + await runNxCommandAsync(proj, `generate nx-vue3-vite:library ${library}`); + + // Verify `devDepndencies` after running the generator + packageJson = readJson(proj, 'package.json'); + expect(packageJson.devDependencies[packageName]).toEqual( + `^${oldVersion}`, + ); + }); }); describe('--test', () => { @@ -179,11 +191,11 @@ describe('library e2e', () => { ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); }); - it.only('lints and uses Vitest as testing framework by default', async () => { - // Reset project to verify correct dependencies are installed - proj = uniq('vue3-vite'); - ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); + afterAll(() => { + cleanup(proj); + }); + it('lints and uses Vitest as testing framework by default', async () => { // Create library const library = uniq('lib-test'); await runNxCommandAsync( @@ -211,7 +223,7 @@ describe('library e2e', () => { // Lint const lintResult = await runNxCommandAsync(proj, `lint ${library}`); - expect(lintResult.stdout).toContain('All files pass linting.'); + expect(lintResult.stdout).toContain('All files pass linting'); }); it('runs tests with Vitest when `test` equals to "vitest"', async () => { @@ -236,11 +248,11 @@ describe('library e2e', () => { ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); }); - it('lints and uses Jest as testing framework when `test` equals to "jest"', async () => { - // Reset project to verify correct dependencies are installed - proj = uniq('vue3-vite'); - ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); + afterAll(() => { + cleanup(proj); + }); + it('lints and uses Jest as testing framework when `test` equals to "jest"', async () => { // Create library const library = uniq('lib-test'); await runNxCommandAsync( @@ -268,7 +280,7 @@ describe('library e2e', () => { // Lint const lintResult = await runNxCommandAsync(proj, `lint ${library}`); - expect(lintResult.stdout).toContain('All files pass linting.'); + expect(lintResult.stdout).toContain('All files pass linting'); }); it('runs tests with Jest when `test` equals to "jest"', async () => { diff --git a/e2e/vue3-vite-e2e/tests/utils/async-commands.ts b/e2e/vue3-vite-e2e/tests/utils/async-commands.ts index 7dba4c2..db9abf3 100644 --- a/e2e/vue3-vite-e2e/tests/utils/async-commands.ts +++ b/e2e/vue3-vite-e2e/tests/utils/async-commands.ts @@ -44,5 +44,9 @@ export function runNxCommandAsync( }, ): Promise<{ stdout: string; stderr: string }> { const pmc = getPackageManagerCommand(); - return runCommandAsync(projectPath, `${pmc.exec} nx ${command}`, opts); + return runCommandAsync( + projectPath, + `NX_DAEMON=false ${pmc.exec} nx ${command}`, + opts, + ); } diff --git a/e2e/vue3-vite-e2e/tests/vue3-vite.spec.ts b/e2e/vue3-vite-e2e/tests/vue3-vite.spec.ts index 6bbd03b..ec07c4a 100644 --- a/e2e/vue3-vite-e2e/tests/vue3-vite.spec.ts +++ b/e2e/vue3-vite-e2e/tests/vue3-vite.spec.ts @@ -1,3 +1,4 @@ +import { getPackageManagerCommand } from '@nx/devkit'; import { checkFilesExist, cleanup, @@ -16,209 +17,262 @@ jest.setTimeout(90000); describe('vue3-vite e2e', () => { let proj: string; - beforeAll(() => { - proj = uniq('vue3-vite'); - ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); - }); + describe('basic app checks', () => { + beforeAll(() => { + proj = uniq('vue3-vite'); + ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); + }); - afterAll(() => { - cleanup(proj); - }); + afterAll(() => { + cleanup(proj); + }); - it('should create and build vue3-vite app', async () => { - // Create app - const app = uniq('vue3-vite'); - await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); - - // Check files exist - checkFilesExist(proj, [ - `apps/${app}/index.html`, - `apps/${app}/postcss.config.js`, - `apps/${app}/project.json`, - `apps/${app}/src/app/main.ts`, - `apps/${app}/tsconfig.json`, - `apps/${app}/vite.config.ts`, - `nx.json`, - `package.json`, - `tsconfig.base.json`, - ]); - - // Build app - const result = await runNxCommandAsync(proj, `build ${app}`); - expect(result.stdout).toContain('Build complete'); - }); + it('should create and build vue3-vite app', async () => { + // Create app + const app = uniq('vue3-vite'); + await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); - it('should make a copy of `package.json` to `dist` if it exists', async () => { - // Create app - const app = uniq('vue3-vite'); - await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); + // Check files exist + checkFilesExist(proj, [ + `apps/${app}/index.html`, + `apps/${app}/postcss.config.mjs`, + `apps/${app}/project.json`, + `apps/${app}/src/app/main.ts`, + `apps/${app}/tsconfig.json`, + `apps/${app}/vite.config.ts`, + `nx.json`, + `package.json`, + `tsconfig.base.json`, + ]); - // Create `package.json` - const stringifiedPackageJson = JSON.stringify({ - name: app, - version: '0.0.1', + // Build app + const result = await runNxCommandAsync(proj, `build ${app}`); + expect(result.stdout).toContain('Build complete'); }); - updateFile('package.json', stringifiedPackageJson, `${proj}/apps/${app}`); - checkFilesExist(proj, [`apps/${app}/package.json`]); - // Build app - const result = await runNxCommandAsync(proj, `build ${app}`); - expect(result.stdout).toContain('Build complete'); + it('should make a copy of `package.json` to `dist` if it exists', async () => { + // Create app + const app = uniq('vue3-vite'); + await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); - // Verify `package.json` is copied - const copiedPackageJson = readJson(proj, `dist/apps/${app}/package.json`); - expect(JSON.stringify(copiedPackageJson)).toEqual(stringifiedPackageJson); - }); + // Create `package.json` + const stringifiedPackageJson = JSON.stringify({ + name: app, + version: '0.0.1', + }); + updateFile('package.json', stringifiedPackageJson, `${proj}/apps/${app}`); + checkFilesExist(proj, [`apps/${app}/package.json`]); - it('should not make a copy of `package.json` to `dist` if it does not exist', async () => { - // Create app - const app = uniq('vue3-vite'); - await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); + // Build app + const result = await runNxCommandAsync(proj, `build ${app}`); + expect(result.stdout).toContain('Build complete'); - // Build app - const result = await runNxCommandAsync(proj, `build ${app}`); - expect(result.stdout).toContain('Build complete'); + // Verify `package.json` is copied + const copiedPackageJson = readJson(proj, `dist/apps/${app}/package.json`); + expect(JSON.stringify(copiedPackageJson)).toEqual(stringifiedPackageJson); + }); - // Verify `package.json` does not exist in app folder - const packageJsonInApp = `${proj}/apps/${app}/package.json`; - expect(exists(packageJsonInApp)).toEqual(false); + it('should not make a copy of `package.json` to `dist` if it does not exist', async () => { + // Create app + const app = uniq('vue3-vite'); + await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); - // Verify `package.json` does not exist in `dist` folder - const packageJsonInDist = `${proj}/dist/apps/${app}/package.json`; - expect(exists(packageJsonInDist)).toEqual(false); - }); + // Build app + const result = await runNxCommandAsync(proj, `build ${app}`); + expect(result.stdout).toContain('Build complete'); - it('should pass lint check', async () => { - // Create app - const app = uniq('vue3-vite'); - await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); + // Verify `package.json` does not exist in app folder + const packageJsonInApp = `${proj}/apps/${app}/package.json`; + expect(exists(packageJsonInApp)).toEqual(false); - // Lint - const lintResult = await runNxCommandAsync(proj, `lint ${app}`); - expect(lintResult.stdout).toContain('All files pass linting.'); - }); + // Verify `package.json` does not exist in `dist` folder + const packageJsonInDist = `${proj}/dist/apps/${app}/package.json`; + expect(exists(packageJsonInDist)).toEqual(false); + }); - it('should not overwrite `dependencies` in `package.json`', async () => { - // Install Vue 2 - const packageName = 'vue'; - const oldVersion = '^2.7.16'; - await runCommandAsync( - proj, - `npm install ${packageName}@${oldVersion} --force --save`, - ); - - // Verify `dependencies` after install - let packageJson = readJson(proj, 'package.json'); - expect(packageJson.dependencies[packageName]).toEqual(oldVersion); - - // Create app - const app = uniq('vue3-vite-dep'); - await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); - - // Verify `dependencies` after running the generator - packageJson = readJson(proj, 'package.json'); - expect(packageJson.dependencies[packageName]).toEqual(oldVersion); - }); + it('should pass lint check', async () => { + // Create app + const app = uniq('vue3-vite'); + await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); - it('should not overwrite `devDependencies` in `package.json`', async () => { - // Install Vite 3 - const packageName = 'vite'; - const oldVersion = '^3.2.10'; - await runCommandAsync( - proj, - `npm install ${packageName}@${oldVersion} --force --save-dev`, - ); - - // Verify `dependencies` after install - let packageJson = readJson(proj, 'package.json'); - expect(packageJson.devDependencies[packageName]).toEqual(oldVersion); - - // Create app - const app = uniq('vue3-vite-dev-dep'); - await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); - - // Verify `devDepndencies` after running the generator - packageJson = readJson(proj, 'package.json'); - expect(packageJson.devDependencies[packageName]).toEqual(oldVersion); - }); + // Lint + const lintResult = await runNxCommandAsync(proj, `lint ${app}`); + expect(lintResult.stdout).toContain('All files pass linting'); + }); - describe('--directory', () => { - it('should create app in the specified directory and add tags to nx.json', async () => { - const plugin = uniq('vue3-vite'); - await runNxCommandAsync( - proj, - `generate nx-vue3-vite:app ${plugin} --directory subdir/${plugin} --tags e2etag,e2ePackage`, - ); + describe('--directory', () => { + it('should create app in the specified directory and add tags to nx.json', async () => { + const plugin = uniq('vue3-vite'); + await runNxCommandAsync( + proj, + `generate nx-vue3-vite:app ${plugin} --directory subdir/${plugin} --tags e2etag,e2ePackage`, + ); - expect(() => - checkFilesExist(proj, [`apps/subdir/${plugin}/vite.config.ts`]), - ).not.toThrow(); - const projectJson = readJson(proj, `apps/subdir/${plugin}/project.json`); - expect(projectJson.tags).toEqual(['e2etag', 'e2ePackage']); + expect(() => + checkFilesExist(proj, [`apps/subdir/${plugin}/vite.config.ts`]), + ).not.toThrow(); + const projectJson = readJson( + proj, + `apps/subdir/${plugin}/project.json`, + ); + expect(projectJson.tags).toEqual(['e2etag', 'e2ePackage']); + }); }); - }); - describe('--alias', () => { - it('should use global path alias by default', async () => { - // Create app - const app = uniq('vue3-vite'); - await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); + describe('--alias', () => { + it('should use global path alias by default', async () => { + // Create app + const app = uniq('vue3-vite'); + await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); - // Read paths - const tsConfigJson = readJson(proj, `apps/${app}/tsconfig.json`); - const { baseUrl, paths } = tsConfigJson.compilerOptions; + // Read paths + const tsConfigJson = readJson(proj, `apps/${app}/tsconfig.json`); + const { baseUrl, paths } = tsConfigJson.compilerOptions; - // Verify `tsConfigJson.compilerOptions.paths` - expect(baseUrl).toBeUndefined(); - expect(paths).toBeUndefined(); + // Verify `tsConfigJson.compilerOptions.paths` + expect(baseUrl).toBeUndefined(); + expect(paths).toBeUndefined(); - // Verify `vite.config.ts` - const viteConfig = readFile(proj, `apps/${app}/vite.config.ts`); - expect(viteConfig).toMatch( - /import\s{.*tsconfigBaseAliases.*}\sfrom\s'nx-vue3-vite'/, - ); - expect(viteConfig).toContain('...tsconfigBaseAliases(__dirname),'); + // Verify `vite.config.ts` + const viteConfig = readFile(proj, `apps/${app}/vite.config.ts`); + expect(viteConfig).toMatch( + /import\s{.*tsconfigBaseAliases.*}\sfrom\s'nx-vue3-vite'/, + ); + expect(viteConfig).toContain('...tsconfigBaseAliases(__dirname),'); + }); + + it('should use local path alias when `alias` equals to "local"', async () => { + // Create app + const app = uniq('vue3-vite'); + await runNxCommandAsync( + proj, + `generate nx-vue3-vite:app ${app} --alias local`, + ); + + // Read paths + const tsConfigJson = readJson(proj, `apps/${app}/tsconfig.json`); + const { paths } = tsConfigJson.compilerOptions; + + // Verify `tsConfigJson.compilerOptions.paths` + expect(Object.keys(paths)).toHaveLength(3); + expect(paths).toMatchObject({ + '@assets/*': ['./src/assets/*'], + '@app/*': ['./src/app/*'], + '@public/*': ['./src/public/*'], + }); + + // Verify `vite.config.ts` + const viteConfig = readFile(proj, `apps/${app}/vite.config.ts`); + expect(viteConfig).not.toContain('tsconfigBaseAliases'); + expect(viteConfig).toContain( + "'@assets/': `${path.resolve(__dirname, './src/assets')}/`", + ); + expect(viteConfig).toContain( + "'@app/': `${path.resolve(__dirname, './src/app')}/`", + ); + expect(viteConfig).toContain( + "'@public/': `${path.resolve(__dirname, './src/public')}/", + ); + }); + + it('should fail when `alias` is not a valid value', async () => { + // Create app + const app = uniq('vue3-vite'); + const wrongValue = 'hello'; + const createAppCommand = `generate nx-vue3-vite:app ${app} --alias ${wrongValue}`; + + // Expect it to throw an error + await expect( + runNxCommandAsync(proj, createAppCommand), + ).rejects.toThrow(); + + // Silence error to verify error message, because the error message thrown + // by `runNxCommandAsync` looks like `Command failed: {command}`, which is + // not detailed enough. + const result = await runNxCommandAsync(proj, createAppCommand, { + silenceError: true, + }); + expect(result.stdout).toContain( + `Property 'alias' does not match the schema. '${wrongValue}' should be one of local,global.`, + ); + }); }); + }); - it('should use local path alias when `alias` equals to "local"', async () => { - // Create app - const app = uniq('vue3-vite'); - await runNxCommandAsync( + describe('update configuration', () => { + beforeEach(() => { + proj = uniq('vue3-vite'); + ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); + }); + + afterEach(() => { + cleanup(proj); + }); + + it('should not overwrite `dependencies` in `package.json`', async () => { + const pmc = getPackageManagerCommand(); + + // Install Vue 2 + const packageName = 'vue'; + const oldVersion = '^2.7.16'; + await runCommandAsync( proj, - `generate nx-vue3-vite:app ${app} --alias local`, + `${pmc.install} ${packageName}@${oldVersion} --force --save`, ); - // Read paths - const tsConfigJson = readJson(proj, `apps/${app}/tsconfig.json`); - const { paths } = tsConfigJson.compilerOptions; + // Verify `dependencies` after install + let packageJson = readJson(proj, 'package.json'); + expect(packageJson.dependencies[packageName]).toEqual(oldVersion); - // Verify `tsConfigJson.compilerOptions.paths` - expect(Object.keys(paths)).toHaveLength(3); - expect(paths).toMatchObject({ - '@assets/*': ['./src/assets/*'], - '@app/*': ['./src/app/*'], - '@public/*': ['./src/public/*'], - }); + // Create app + const app = uniq('vue3-vite-dep'); + await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); - // Verify `vite.config.ts` - const viteConfig = readFile(proj, `apps/${app}/vite.config.ts`); - expect(viteConfig).not.toContain('tsconfigBaseAliases'); - expect(viteConfig).toContain( - "'@assets/': `${path.resolve(__dirname, './src/assets')}/`", + // Verify `dependencies` after running the generator + packageJson = readJson(proj, 'package.json'); + expect(packageJson.dependencies[packageName]).toEqual(oldVersion); + }); + + it('should not overwrite `devDependencies` in `package.json`', async () => { + const pmc = getPackageManagerCommand(); + + // Install Vite 3 + const packageName = 'vite'; + const oldVersion = '5.2.5'; + await runCommandAsync( + proj, + `${pmc.install} -D ${packageName}@${oldVersion} --force`, ); - expect(viteConfig).toContain( - "'@app/': `${path.resolve(__dirname, './src/app')}/`", + + // Verify `dependencies` after install + let packageJson = readJson(proj, 'package.json'); + expect(packageJson.devDependencies[packageName]).toEqual( + `^${oldVersion}`, ); - expect(viteConfig).toContain( - "'@public/': `${path.resolve(__dirname, './src/public')}/", + + // Create app + const app = uniq('vue3-vite-dev-dep'); + await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); + + // Verify `devDependencies` after running the generator + packageJson = readJson(proj, 'package.json'); + expect(packageJson.devDependencies[packageName]).toEqual( + `^${oldVersion}`, ); }); + }); - it('lints and builds with global paths when `alias` is "global"', async () => { - // Reset project to avoid issues with previous project state + describe('alias global', () => { + beforeAll(() => { proj = uniq('vue3-vite'); ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); + }); + afterAll(() => { + cleanup(proj); + }); + + it('lints and builds with global paths when `alias` is "global"', async () => { // Create app const app = uniq('vue3-vite'); await runNxCommandAsync( @@ -243,41 +297,26 @@ describe('vue3-vite e2e', () => { // Lint const lintResult = await runNxCommandAsync(proj, `lint ${app}`); - expect(lintResult.stdout).toContain('All files pass linting.'); + expect(lintResult.stdout).toContain('All files pass linting'); // Build app const result = await runNxCommandAsync(proj, `build ${app}`); expect(result.stdout).toContain('Build complete'); }); - - it('should fail when `alias` is not a valid value', async () => { - // Create app - const app = uniq('vue3-vite'); - const wrongValue = 'hello'; - const createAppCommand = `generate nx-vue3-vite:app ${app} --alias ${wrongValue}`; - - // Expect it to throw an error - await expect(runNxCommandAsync(proj, createAppCommand)).rejects.toThrow(); - - // Silence error to verify error message, because the error message thrown - // by `runNxCommandAsync` looks like `Command failed: {command}`, which is - // not detailed enough. - const result = await runNxCommandAsync(proj, createAppCommand, { - silenceError: true, - }); - expect(result.stdout).toContain( - `Property 'alias' does not match the schema. '${wrongValue}' should be one of local,global.`, - ); - }); }); describe('--test', () => { - describe('lints', () => { - it('lints and uses Vitest as testing framework by default', async () => { - // Reset project to verify correct dependencies are installed + describe('vitest', () => { + beforeAll(() => { proj = uniq('vue3-vite'); ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); + }); + afterAll(() => { + cleanup(proj); + }); + + it('lints and uses Vitest as testing framework by default', async () => { // Create app const app = uniq('vue3-vite'); await runNxCommandAsync(proj, `generate nx-vue3-vite:app ${app}`); @@ -302,14 +341,49 @@ describe('vue3-vite e2e', () => { // Lint const lintResult = await runNxCommandAsync(proj, `lint ${app}`); - expect(lintResult.stdout).toContain('All files pass linting.'); + expect(lintResult.stdout).toContain('All files pass linting'); }); - it('lints and uses Jest as testing framework when `test` equals to "jest"', async () => { - // Reset project to verify correct dependencies are installed + it('runs tests with Vitest when `test` equals to "vitest"', async () => { + // Create app + const app = uniq('vue3-vite'); + await runNxCommandAsync( + proj, + `generate nx-vue3-vite:app ${app} --test vitest`, + ); + + // Runs tests + const testResult = await runNxCommandAsync(proj, `test ${app}`); + expect(testResult.stdout).toContain( + `Successfully ran target test for project ${app}`, + ); + }); + + it('builds with Vitest when `test` equals to "vitest"', async () => { + // Create app + const app = uniq('vue3-vite'); + await runNxCommandAsync( + proj, + `generate nx-vue3-vite:app ${app} --test vitest`, + ); + + // Build app + const result = await runNxCommandAsync(proj, `build ${app}`); + expect(result.stdout).toContain('Build complete'); + }); + }); + + describe('jest', () => { + beforeAll(() => { proj = uniq('vue3-vite'); ensureNxProject('nx-vue3-vite', 'dist/packages/vue3-vite', proj); + }); + + afterAll(() => { + cleanup(proj); + }); + it('lints and uses Jest as testing framework when `test` equals to "jest"', async () => { // Create app const app = uniq('vue3-vite'); await runNxCommandAsync( @@ -337,24 +411,7 @@ describe('vue3-vite e2e', () => { // Lint const lintResult = await runNxCommandAsync(proj, `lint ${app}`); - expect(lintResult.stdout).toContain('All files pass linting.'); - }); - }); - - describe('runs tests', () => { - it('runs tests with Vitest when `test` equals to "vitest"', async () => { - // Create app - const app = uniq('vue3-vite'); - await runNxCommandAsync( - proj, - `generate nx-vue3-vite:app ${app} --test vitest`, - ); - - // Runs tests - const testResult = await runNxCommandAsync(proj, `test ${app}`); - expect(testResult.stdout).toContain( - `Successfully ran target test for project ${app}`, - ); + expect(lintResult.stdout).toContain('All files pass linting'); }); it('runs tests with Jest when `test` equals to "jest"', async () => { @@ -371,15 +428,13 @@ describe('vue3-vite e2e', () => { `Successfully ran target test for project ${app}`, ); }); - }); - describe('builds', () => { - it('builds with Vitest when `test` equals to "vitest"', async () => { + it('builds with Jest when `test` equals to "jest"', async () => { // Create app const app = uniq('vue3-vite'); await runNxCommandAsync( proj, - `generate nx-vue3-vite:app ${app} --test vitest`, + `generate nx-vue3-vite:app ${app} --test jest`, ); // Build app @@ -387,38 +442,27 @@ describe('vue3-vite e2e', () => { expect(result.stdout).toContain('Build complete'); }); - it('builds with Jest when `test` equals to "jest"', async () => { + it('should fail when `test` is not a valid value', async () => { // Create app const app = uniq('vue3-vite'); - await runNxCommandAsync( - proj, - `generate nx-vue3-vite:app ${app} --test jest`, + const wrongValue = 'hello'; + const createAppCommand = `generate nx-vue3-vite:app ${app} --test ${wrongValue}`; + + // Expect it to throw an error + await expect( + runNxCommandAsync(proj, createAppCommand), + ).rejects.toThrow(); + + // Silence error to verify error message, because the error message thrown + // by `runNxCommandAsync` looks like `Command failed: {command}`, which is + // not detailed enough. + const result = await runNxCommandAsync(proj, createAppCommand, { + silenceError: true, + }); + expect(result.stdout).toContain( + `Property 'test' does not match the schema. '${wrongValue}' should be one of vitest,jest.`, ); - - // Build app - const result = await runNxCommandAsync(proj, `build ${app}`); - expect(result.stdout).toContain('Build complete'); - }); - }); - - it('should fail when `test` is not a valid value', async () => { - // Create app - const app = uniq('vue3-vite'); - const wrongValue = 'hello'; - const createAppCommand = `generate nx-vue3-vite:app ${app} --test ${wrongValue}`; - - // Expect it to throw an error - await expect(runNxCommandAsync(proj, createAppCommand)).rejects.toThrow(); - - // Silence error to verify error message, because the error message thrown - // by `runNxCommandAsync` looks like `Command failed: {command}`, which is - // not detailed enough. - const result = await runNxCommandAsync(proj, createAppCommand, { - silenceError: true, }); - expect(result.stdout).toContain( - `Property 'test' does not match the schema. '${wrongValue}' should be one of vitest,jest.`, - ); }); }); }); diff --git a/package.json b/package.json index 99f9b92..86976ee 100644 --- a/package.json +++ b/package.json @@ -4,60 +4,88 @@ "version": "0.27.0", "license": "MIT", "scripts": { - "nx": "nx", - "build": "nx build vue3-vite", - "test": "nx test vue3-vite", - "lint": "nx workspace-lint && nx lint vue3-vite", - "e2e": "nx e2e vue3-vite-e2e", + "affected": "nx affected", "affected:apps": "nx affected:apps", - "affected:libs": "nx affected:libs", "affected:build": "nx affected:build", + "affected:dep-graph": "nx affected:dep-graph", "affected:e2e": "nx affected:e2e", - "affected:test": "nx affected:test", + "affected:libs": "nx affected:libs", "affected:lint": "nx affected:lint", - "affected:dep-graph": "nx affected:dep-graph", - "affected": "nx affected", + "affected:test": "nx affected:test", + "build": "nx build vue3-vite", + "commit-msg": "node tools/scripts/verifyCommit.js", + "dep-graph": "nx dep-graph", + "e2e": "nx e2e vue3-vite-e2e", "format": "nx format:write", - "format:write": "nx format:write", "format:check": "nx format:check", - "update": "nx migrate latest", - "dep-graph": "nx dep-graph", + "format:write": "nx format:write", "help": "nx help", - "commit-msg": "node tools/scripts/verifyCommit.js", - "prepare": "husky install" + "lint": "nx workspace-lint && nx lint vue3-vite", + "nx": "nx", + "prepare": "husky install", + "test": "nx test vue3-vite", + "update": "nx migrate latest" }, "private": true, "devDependencies": { + "@babel/core": "^7.23.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/preset-env": "^7.24.5", + "@cypress/code-coverage": "^3.12.39", "@cypress/vite-dev-server": "^5.0.7", + "@cypress/vue": "^6.0.0", + "@intlify/eslint-plugin-vue-i18n": "^2.0.0", + "@nx/cypress": "*", "@nx/devkit": "18.3.4", + "@nx/eslint": "18.3.4", "@nx/eslint-plugin": "18.3.4", "@nx/jest": "18.3.4", "@nx/js": "18.3.4", - "@nx/eslint": "18.3.4", + "@nx/vite": "^18.3.4", "@nx/workspace": "18.3.4", + "@samatech/postcss-basics": "^0.7.4", "@types/jest": "29.5.12", "@types/node": "20.12.11", "@typescript-eslint/eslint-plugin": "7.8.0", "@typescript-eslint/parser": "7.8.0", "@vitejs/plugin-vue": "5.0.4", + "@vue/eslint-config-typescript": "^13.0.0", + "@vue/test-utils": "^2.4.6", + "class-transformer": "^0.5.1", "conventional-github-releaser": "^3.1.5", "cypress": "^13.9.0", "dotenv": "16.4.5", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", + "eslint-plugin-cypress": "^3.2.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-vue": "^9.26.0", "fs-extra": "^11.2.0", + "happy-dom": "^14.10.1", "husky": "^8.0.3", "jest": "29.7.0", "nx": "18.3.4", "picocolors": "^1.0.0", + "postcss": "^8.4.38", "prettier": "^3.2.5", "readline": "^1.3.0", "rollup": "^4.17.2", + "stylelint": "^16.5.0", + "stylelint-config-standard": "^36.0.0", "ts-jest": "^29.1.2", "ts-node": "~10.9.2", + "tsconfig": "^7.0.0", "tslib": "^2.6.2", "typescript": "~5.4.5", "vite": "^5.2.11", - "vitepress": "^0.22.4" + "vitepress": "^0.22.4", + "vitest": "^1.6.0", + "vue-eslint-parser": "^9.4.2" + }, + "dependencies": { + "date-fns": "^3.6.0", + "vue": "^3.4.27", + "vue-i18n": "^9.13.1", + "vue-router": "^4.3.2" } } diff --git a/packages/vue3-vite/src/generators/cypress/generator.ts b/packages/vue3-vite/src/generators/cypress/generator.ts index ae8429e..79dd3b7 100644 --- a/packages/vue3-vite/src/generators/cypress/generator.ts +++ b/packages/vue3-vite/src/generators/cypress/generator.ts @@ -2,7 +2,6 @@ import { addProjectConfiguration, formatFiles, generateFiles, - getWorkspaceLayout, names, offsetFromRoot, Tree, @@ -12,6 +11,7 @@ import * as path from 'path'; import { CypressGeneratorSchema } from './schema'; import { CypressDevDependencies } from '../../util/defaults'; import { + getAppsDir, parseTags, runTasksInSerial, updateDependencies, @@ -36,10 +36,7 @@ function normalizeOptions( const projectDirectory = options.directory ? names(options.directory).fileName : name; - const projectRoot = joinPathFragments( - getWorkspaceLayout(host).appsDir, - projectDirectory, - ); + const projectRoot = joinPathFragments(getAppsDir(host), projectDirectory); const parsedTags = parseTags(options.tags); return { diff --git a/packages/vue3-vite/src/generators/docs/generator.ts b/packages/vue3-vite/src/generators/docs/generator.ts index 0eedd5b..a1d2f1a 100644 --- a/packages/vue3-vite/src/generators/docs/generator.ts +++ b/packages/vue3-vite/src/generators/docs/generator.ts @@ -2,7 +2,6 @@ import { addProjectConfiguration, formatFiles, generateFiles, - getWorkspaceLayout, names, offsetFromRoot, Tree, @@ -18,6 +17,7 @@ import { recommendedExtensions, } from '../../util/defaults'; import { + getAppsDir, parseTags, runTasksInSerial, updateDependencies, @@ -42,10 +42,7 @@ function normalizeOptions( const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); const projectTitle = options.title || projectName; - const projectRoot = joinPathFragments( - getWorkspaceLayout(host).appsDir, - projectDirectory, - ); + const projectRoot = joinPathFragments(getAppsDir(host), projectDirectory); const parsedTags = parseTags(options.tags); return { diff --git a/packages/vue3-vite/src/generators/library/files/postcss.config.js.template b/packages/vue3-vite/src/generators/library/files/postcss.config.js.template deleted file mode 100644 index b82655a..0000000 --- a/packages/vue3-vite/src/generators/library/files/postcss.config.js.template +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - plugins: [] -} \ No newline at end of file diff --git a/packages/vue3-vite/src/generators/library/files/postcss.config.mjs.template b/packages/vue3-vite/src/generators/library/files/postcss.config.mjs.template new file mode 100644 index 0000000..1ffb2ee --- /dev/null +++ b/packages/vue3-vite/src/generators/library/files/postcss.config.mjs.template @@ -0,0 +1,3 @@ +export default { + plugins: [], +} diff --git a/packages/vue3-vite/src/generators/library/generator.ts b/packages/vue3-vite/src/generators/library/generator.ts index 3824bbf..1f54eca 100644 --- a/packages/vue3-vite/src/generators/library/generator.ts +++ b/packages/vue3-vite/src/generators/library/generator.ts @@ -22,6 +22,7 @@ import { } from '../../util/defaults'; import { getCaseAwareFileName, + getLibsDir, parseTags, updateDependencies, } from '../../util/utils'; @@ -46,8 +47,7 @@ function normalizeOptions( ): NormalizedSchema { const { layoutDirectory, projectDirectory: libraryDirectory } = extractLayoutDirectory(options.directory); - const { libsDir: defaultLibsDir } = getWorkspaceLayout(host); - const libsDir = layoutDirectory ?? defaultLibsDir; + const libsDir = layoutDirectory ?? getLibsDir(host); const name = names(options.name).fileName; const fullLibraryDirectory = libraryDirectory @@ -172,7 +172,7 @@ export default async function (host: Tree, options: LibraryGeneratorSchema) { lintFilePatterns: [`${libraryRoot}/**/*.{js,jsx,ts,tsx,vue}`], }, }, - test: generateTestTarget(libraryRoot, testFramework), + test: generateTestTarget(libraryRoot, testFramework, libraryName), }, tags: normalizedOptions.parsedTags, }); diff --git a/packages/vue3-vite/src/generators/vue3-vite/files/postcss.config.js.template b/packages/vue3-vite/src/generators/vue3-vite/files/postcss.config.js.template deleted file mode 100644 index 07317e0..0000000 --- a/packages/vue3-vite/src/generators/vue3-vite/files/postcss.config.js.template +++ /dev/null @@ -1,7 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ - -module.exports = { - plugins: [ - ...require('@samatech/postcss-basics')(), - ], -}; diff --git a/packages/vue3-vite/src/generators/vue3-vite/files/postcss.config.mjs.template b/packages/vue3-vite/src/generators/vue3-vite/files/postcss.config.mjs.template new file mode 100644 index 0000000..fe007cb --- /dev/null +++ b/packages/vue3-vite/src/generators/vue3-vite/files/postcss.config.mjs.template @@ -0,0 +1,5 @@ +import postcssBasics from '@samatech/postcss-basics' + +export default { + plugins: [...postcssBasics()], +} diff --git a/packages/vue3-vite/src/generators/vue3-vite/generator.ts b/packages/vue3-vite/src/generators/vue3-vite/generator.ts index 2a0a9d8..0093e9f 100644 --- a/packages/vue3-vite/src/generators/vue3-vite/generator.ts +++ b/packages/vue3-vite/src/generators/vue3-vite/generator.ts @@ -2,7 +2,6 @@ import { addProjectConfiguration, formatFiles, generateFiles, - getWorkspaceLayout, names, offsetFromRoot, Tree, @@ -19,7 +18,12 @@ import { JestDevDependencies, VitestDevDependencies, } from '../../util/defaults'; -import { parseTags, updateDependencies, updateScripts } from '../../util/utils'; +import { + getAppsDir, + parseTags, + updateDependencies, + updateScripts, +} from '../../util/utils'; import { PathAlias } from '../../util/path-alias'; import { TestFramework } from '../../util/test-framework'; import { generateTestTarget } from '../../util/generate-test-target'; @@ -44,10 +48,7 @@ function normalizeOptions( : name; const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); const projectTitle = options.title || projectName; - const projectRoot = joinPathFragments( - getWorkspaceLayout(host).appsDir, - projectDirectory, - ); + const projectRoot = joinPathFragments(getAppsDir(host), projectDirectory); const parsedTags = parseTags(options.tags); // Default to global paths const useLocalAlias = options.alias === PathAlias.Local; @@ -161,7 +162,7 @@ export default async function (host: Tree, options: Vue3ViteGeneratorSchema) { lintFilePatterns: [`${projectRoot}/**/*.{js,jsx,ts,tsx,vue}`], }, }, - test: generateTestTarget(projectRoot, testFramework), + test: generateTestTarget(projectRoot, testFramework, projectName), }, tags: normalizedOptions.parsedTags, }); diff --git a/packages/vue3-vite/src/util/defaults.ts b/packages/vue3-vite/src/util/defaults.ts index 8a1e4e9..4f99be7 100644 --- a/packages/vue3-vite/src/util/defaults.ts +++ b/packages/vue3-vite/src/util/defaults.ts @@ -16,7 +16,7 @@ export const jestGlobalsVersion = '^29.7.0'; export const vue3JestVersion = '^29.2.6'; export const babelPresetEnvVersion = '^7.24.5'; export const postcssVersion = '^8.4.38'; -export const postcssBasicsVersion = '^0.7.3'; +export const postcssBasicsVersion = '^0.7.4'; export const stylelintVersion = '^16.5.0'; export const stylelintConfigVersion = '^36.0.0'; export const tslibVersion = '^2.6.2'; diff --git a/packages/vue3-vite/src/util/generate-test-target.ts b/packages/vue3-vite/src/util/generate-test-target.ts index 857ea25..cbbdb80 100644 --- a/packages/vue3-vite/src/util/generate-test-target.ts +++ b/packages/vue3-vite/src/util/generate-test-target.ts @@ -3,12 +3,13 @@ import { TestFramework } from './test-framework'; export const generateTestTarget = ( projectRoot: string, testFramework: TestFramework, + projectName: string, ) => { const useVitest = testFramework === TestFramework.Vitest; const executor = useVitest ? '@nx/vite:test' : '@nx/jest:jest'; const config = useVitest ? { - config: 'vite.config.ts', + config: `${projectRoot}/vite.config.ts`, } : { jestConfig: `${projectRoot}/jest.config.ts`, @@ -16,7 +17,7 @@ export const generateTestTarget = ( return { executor, - outputs: ['coverage/libs/e2e/apps'], + outputs: [`{workspaceRoot}/coverage/apps/${projectName}`], options: { ...config, passWithNoTests: true, diff --git a/packages/vue3-vite/src/util/utils.ts b/packages/vue3-vite/src/util/utils.ts index 47acfd8..092be2b 100644 --- a/packages/vue3-vite/src/util/utils.ts +++ b/packages/vue3-vite/src/util/utils.ts @@ -6,6 +6,7 @@ import { GeneratorCallback, updateJson, names, + getWorkspaceLayout, } from '@nx/devkit'; import { jestProjectGenerator } from '@nx/jest'; @@ -99,6 +100,16 @@ export function parseTags(tagsStr: string): string[] { return tagsStr ? tagsStr.split(',').map((s) => s.trim()) : []; } +export function getAppsDir(host: Tree) { + const dir = getWorkspaceLayout(host).appsDir; + return !dir || dir === '.' ? 'apps' : dir; +} + +export function getLibsDir(host: Tree) { + const dir = getWorkspaceLayout(host).libsDir; + return !dir || dir === '.' ? 'libs' : dir; +} + export async function addJest(host: Tree, projectName: string) { const jestTask = await jestProjectGenerator(host, { project: projectName, diff --git a/tsconfig.base.json b/tsconfig.base.json index a6e251e..45a3393 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -17,7 +17,8 @@ "baseUrl": ".", "paths": { "nx-vue3-vite": ["packages/vue3-vite/src/index.ts"] - } + }, + "resolveJsonModule": true }, "exclude": ["node_modules", "tmp"] }