Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b3d661e

Browse filesBrowse files
authored
feat: use a --bare flag to generate a template without too much boilerplate (#636)
Closes #112 Closes #186 Closes #300 Closes #637
1 parent d4999b7 commit b3d661e
Copy full SHA for b3d661e

File tree

9 files changed

+128
-21
lines changed
Filter options

9 files changed

+128
-21
lines changed

‎.github/workflows/ci.yml

Copy file name to clipboardExpand all lines: .github/workflows/ci.yml
+9-8Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ jobs:
4949
node-version: [18, 20, 22]
5050
os: [ubuntu-latest, windows-latest, macos-latest]
5151
verification-script:
52-
- pnpm --filter "\!*typescript*" build
53-
- pnpm --filter "*typescript*" build
54-
- pnpm --filter "*vitest*" test:unit
55-
- pnpm --filter "*eslint*" lint --no-fix --max-warnings=0
56-
- pnpm --filter "*prettier*" format --write --check
52+
- pnpm --filter '!*typescript*' build
53+
- pnpm --filter '*typescript*' build
54+
- pnpm --filter '*vitest*' test:unit
55+
- pnpm --filter '*eslint*' lint --no-fix --max-warnings=0
56+
- pnpm --filter '*prettier*' format --write --check
5757
# FIXME: it's failing now
58-
# - pnpm --filter "*with-tests*" test:unit
58+
# - pnpm --filter '*with-tests*' test:unit
5959
runs-on: ${{ matrix.os }}
6060
continue-on-error: ${{ matrix.os == 'windows-latest' }}
6161
env:
@@ -163,11 +163,12 @@ jobs:
163163

164164
- name: Run build script
165165
working-directory: ./playground
166-
run: pnpm --filter "*${{ matrix.e2e-framework }}*" build
166+
run: pnpm --filter '*${{ matrix.e2e-framework }}*' build
167167

168168
- name: Run e2e test script
169169
working-directory: ./playground
170-
run: pnpm --filter "*${{ matrix.e2e-framework }}*" --workspace-concurrency 1 test:e2e
170+
# bare templates can't pass e2e tests because their page structures don't match the example tests
171+
run: pnpm --filter '*${{ matrix.e2e-framework }}*' --filter '!*bare*' --workspace-concurrency 1 test:e2e
171172

172173
- name: Cypress component testing for projects without Vitest
173174
if: ${{ contains(matrix.e2e-framework, 'cypress') }}

‎index.ts

Copy file name to clipboardExpand all lines: index.ts
+25-3Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import generateReadme from './utils/generateReadme'
1818
import getCommand from './utils/getCommand'
1919
import getLanguage from './utils/getLanguage'
2020
import renderEslint from './utils/renderEslint'
21+
import trimBoilerplate from './utils/trimBoilerplate'
2122

2223
function isValidPackageName(projectName) {
2324
return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(projectName)
@@ -83,7 +84,9 @@ async function init() {
8384
// --playwright
8485
// --eslint
8586
// --eslint-with-prettier (only support prettier through eslint for simplicity)
86-
// --force (for force overwriting)
87+
// in addition to the feature flags, you can also pass the following options:
88+
// --bare (for a barebone template without example code)
89+
// --force (for force overwriting without confirming)
8790

8891
const args = process.argv.slice(2)
8992

@@ -319,8 +322,8 @@ async function init() {
319322
packageName = projectName ?? defaultProjectName,
320323
shouldOverwrite = argv.force,
321324
needsJsx = argv.jsx,
322-
needsTypeScript = argv.ts || argv.typescript,
323-
needsRouter = argv.router || argv['vue-router'],
325+
needsTypeScript = (argv.ts || argv.typescript) as boolean,
326+
needsRouter = (argv.router || argv['vue-router']) as boolean,
324327
needsPinia = argv.pinia,
325328
needsVitest = argv.vitest || argv.tests,
326329
needsPrettier = argv['eslint-with-prettier'],
@@ -563,6 +566,25 @@ async function init() {
563566
)
564567
}
565568

569+
if (argv.bare) {
570+
trimBoilerplate(root, { needsTypeScript, needsRouter })
571+
render('bare/base')
572+
573+
// TODO: refactor the `render` utility to avoid this kind of manual mapping?
574+
if (needsTypeScript) {
575+
render('bare/typescript')
576+
}
577+
if (needsVitest) {
578+
render('bare/vitest')
579+
}
580+
if (needsCypressCT) {
581+
render('bare/cypress-ct')
582+
}
583+
if (needsNightwatchCT) {
584+
render('bare/nightwatch-ct')
585+
}
586+
}
587+
566588
// Instructions:
567589
// Supported package managers: pnpm > yarn > bun > npm
568590
const userAgent = process.env.npm_config_user_agent ?? ''

‎scripts/snapshot.mjs

Copy file name to clipboardExpand all lines: scripts/snapshot.mjs
+11-10Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ if (!/pnpm/.test(process.env.npm_config_user_agent ?? ''))
88
throw new Error("Please use pnpm ('pnpm run snapshot') to generate snapshots!")
99

1010
const featureFlags = [
11+
'bare',
1112
'typescript',
1213
'jsx',
1314
'router',
@@ -54,12 +55,7 @@ function fullCombination(arr) {
5455
}
5556

5657
let flagCombinations = fullCombination(featureFlags)
57-
flagCombinations.push(
58-
['default'],
59-
['router', 'pinia'],
60-
['eslint'],
61-
['eslint-with-prettier'],
62-
)
58+
flagCombinations.push(['default'], ['bare', 'default'], ['eslint'], ['eslint-with-prettier'])
6359

6460
// `--with-tests` are equivalent of `--vitest --cypress`
6561
// Previously it means `--cypress` without `--vitest`.
@@ -85,10 +81,15 @@ for (const flags of flagCombinations) {
8581
}
8682

8783
// Filter out combinations that are not allowed
88-
flagCombinations = flagCombinations.filter(
89-
(combination) =>
90-
!featureFlagsDenylist.some((denylist) => denylist.every((flag) => combination.includes(flag))),
91-
)
84+
flagCombinations = flagCombinations
85+
.filter(
86+
(combination) =>
87+
!featureFlagsDenylist.some((denylist) =>
88+
denylist.every((flag) => combination.includes(flag)),
89+
),
90+
)
91+
// `--bare` is a supplementary flag and should not be used alone
92+
.filter((combination) => !(combination.length === 1 && combination[0] === 'bare'))
9293

9394
const bin = path.posix.relative('../playground/', '../outfile.cjs')
9495

‎template/bare/base/src/App.vue

Copy file name to clipboard
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script setup></script>
2+
3+
<template>
4+
<h1>Hello World</h1>
5+
</template>
6+
7+
<style scoped></style>
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import App from '../App.vue'
2+
3+
describe('App', () => {
4+
it('mounts and renders properly', () => {
5+
cy.mount(App)
6+
cy.get('h1').should('contain', 'Hello World')
7+
})
8+
})
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
describe('App', function () {
2+
before((browser) => {
3+
browser.init()
4+
})
5+
6+
it('mounts and renders properly', async function () {
7+
const appComponent = await browser.mountComponent('/src/App.vue');
8+
9+
browser.expect.element(appComponent).to.be.present;
10+
browser.expect.element('h1').text.to.contain('Hello World');
11+
})
12+
13+
after((browser) => browser.end())
14+
})

‎template/bare/typescript/src/App.vue

Copy file name to clipboard
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script setup lang="ts"></script>
2+
3+
<template>
4+
<h1>Hello World</h1>
5+
</template>
6+
7+
<style scoped></style>
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { describe, it, expect } from 'vitest'
2+
3+
import { mount } from '@vue/test-utils'
4+
import App from '../App.vue'
5+
6+
describe('App', () => {
7+
it('mounts renders properly', () => {
8+
const wrapper = mount(App)
9+
expect(wrapper.text()).toContain('Hello World')
10+
})
11+
})

‎utils/trimBoilerplate.ts

Copy file name to clipboard
+36Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as fs from 'node:fs'
2+
import * as path from 'path'
3+
4+
function replaceContent(filepath: string, replacer: (content: string) => string) {
5+
const content = fs.readFileSync(filepath, 'utf8')
6+
fs.writeFileSync(filepath, replacer(content))
7+
}
8+
9+
export default function trimBoilerplate(rootDir: string, features: Record<string, boolean>) {
10+
const isTs = features.needsTypeScript
11+
const srcDir = path.resolve(rootDir, 'src')
12+
13+
for (const filename of fs.readdirSync(srcDir)) {
14+
// Keep `main.js/ts`, `router`, and `stores` directories
15+
// `App.vue` would be re-rendered in the next step
16+
if (['main.js', 'main.ts', 'router', 'stores'].includes(filename)) {
17+
continue
18+
}
19+
const fullpath = path.resolve(srcDir, filename)
20+
fs.rmSync(fullpath, { recursive: true })
21+
}
22+
23+
// Remove CSS import in the entry file
24+
const entryPath = path.resolve(rootDir, isTs ? 'src/main.ts' : 'src/main.js')
25+
replaceContent(entryPath, (content) => content.replace("import './assets/main.css'\n\n", ''))
26+
27+
// If `router` feature is selected, use an empty router configuration
28+
if (features.needsRouter) {
29+
const routerEntry = path.resolve(srcDir, isTs ? 'router/index.ts' : 'router/index.js')
30+
replaceContent(routerEntry, (content) =>
31+
content
32+
.replace(`import HomeView from '../views/HomeView.vue'\n`, '')
33+
.replace(/routes:\s*\[[\s\S]*?\],/, 'routes: [],'),
34+
)
35+
}
36+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.