@weig_3078/cli-demo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/.eslintrc +73 -0
- package/README.md +1 -0
- package/bin/mvc.js +14 -0
- package/dist/mvc.js +135771 -0
- package/ejs-demo.js +29 -0
- package/lib/ConfigTransform.js +40 -0
- package/lib/Creator.js +29 -0
- package/lib/Generator.js +307 -0
- package/lib/PromptModuleAPI.js +13 -0
- package/lib/create.js +328 -0
- package/lib/generator/babel/index.js +15 -0
- package/lib/generator/linter/index.js +55 -0
- package/lib/generator/linter/template/.eslintrc.js +30 -0
- package/lib/generator/router/index.js +17 -0
- package/lib/generator/router/template/src/App.vue +33 -0
- package/lib/generator/router/template/src/router/index.js +30 -0
- package/lib/generator/router/template/src/views/About.vue +5 -0
- package/lib/generator/router/template/src/views/Home.vue +18 -0
- package/lib/generator/vue/index.js +20 -0
- package/lib/generator/vue/template/public/favicon.ico +0 -0
- package/lib/generator/vue/template/public/index.html +19 -0
- package/lib/generator/vue/template/src/App.vue +29 -0
- package/lib/generator/vue/template/src/assets/logo.png +0 -0
- package/lib/generator/vue/template/src/components/HelloWorld.vue +110 -0
- package/lib/generator/vue/template/src/main.js +8 -0
- package/lib/generator/vuex/index.js +13 -0
- package/lib/generator/vuex/template/src/store/index.js +15 -0
- package/lib/generator/webpack/index.js +27 -0
- package/lib/generator/webpack/template/build/base.config.js +68 -0
- package/lib/generator/webpack/template/build/dev.config.js +19 -0
- package/lib/generator/webpack/template/build/pro.config.js +16 -0
- package/lib/promptModules/babel.js +10 -0
- package/lib/promptModules/linter.js +48 -0
- package/lib/promptModules/router.js +19 -0
- package/lib/promptModules/vuex.js +8 -0
- package/lib/utils/clearConsole.js +13 -0
- package/lib/utils/codemods/injectImports.js +31 -0
- package/lib/utils/codemods/injectOptions.js +27 -0
- package/lib/utils/configTransforms.js +49 -0
- package/lib/utils/executeCommand.js +33 -0
- package/lib/utils/normalizeFilePaths.js +11 -0
- package/lib/utils/sortObject.js +32 -0
- package/lib/utils/stringifyJS.js +12 -0
- package/lib/utils/writeFileTree.js +12 -0
- package/package.json +53 -0
- package/rollup.config.cjs +43 -0
- package/scripts/verify-commit.js +24 -0
package/lib/create.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const fs = require('fs-extra')
|
|
3
|
+
const os = require('os')
|
|
4
|
+
const inquirer = require('inquirer')
|
|
5
|
+
const execa = require('execa')
|
|
6
|
+
const chalk = require('chalk')
|
|
7
|
+
const PromptModuleAPI = require('./PromptModuleAPI')
|
|
8
|
+
const Creator = require('./Creator')
|
|
9
|
+
const Generator = require('./Generator')
|
|
10
|
+
const clearConsole = require('./utils/clearConsole')
|
|
11
|
+
const executeCommand = require('./utils/executeCommand')
|
|
12
|
+
|
|
13
|
+
const DEFAULT_CONFIG_PATH = path.join(os.homedir(), '.mvc-default.json')
|
|
14
|
+
|
|
15
|
+
const REMOTE_TEMPLATES = [
|
|
16
|
+
{
|
|
17
|
+
name: 'vite-full (gitee)',
|
|
18
|
+
repoUrl: 'https://gitee.com/sohucw/vite-full.git',
|
|
19
|
+
repoBranch: 'master',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'custom',
|
|
23
|
+
repoUrl: '',
|
|
24
|
+
repoBranch: '',
|
|
25
|
+
},
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
function logStep(current, total, message) {
|
|
29
|
+
console.log(chalk.cyan(`\n[${current}/${total}] ${message}`))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function logSuccess(message) {
|
|
33
|
+
console.log(chalk.green(`✔ ${message}`))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function printNextSteps(name, skipInstall, pm = 'npm', registry) {
|
|
37
|
+
console.log(chalk.cyan('\nNext steps:'))
|
|
38
|
+
console.log(chalk.white(` cd ${name}`))
|
|
39
|
+
if (skipInstall) console.log(chalk.green(` ${pm} install${registry ? ` --registry=${registry}` : ''}`))
|
|
40
|
+
console.log(chalk.green(` ${pm} run dev\n`))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function promptFeatures() {
|
|
44
|
+
const { featureMode } = await inquirer.prompt([
|
|
45
|
+
{
|
|
46
|
+
name: 'featureMode',
|
|
47
|
+
type: 'list',
|
|
48
|
+
message: 'Pick feature mode:',
|
|
49
|
+
choices: [
|
|
50
|
+
{ name: 'Default config', value: 'default' },
|
|
51
|
+
{ name: 'Manual select', value: 'manual' },
|
|
52
|
+
],
|
|
53
|
+
default: 'default',
|
|
54
|
+
},
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
if (featureMode === 'default') {
|
|
58
|
+
if (await fs.pathExists(DEFAULT_CONFIG_PATH)) {
|
|
59
|
+
return await fs.readJson(DEFAULT_CONFIG_PATH)
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
features: ['babel', 'router', 'vuex', 'linter'],
|
|
63
|
+
historyMode: false,
|
|
64
|
+
eslintConfig: 'airbnb',
|
|
65
|
+
lintOn: ['save'],
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const creator = new Creator()
|
|
70
|
+
const promptModules = getPromptModules()
|
|
71
|
+
const promptAPI = new PromptModuleAPI(creator)
|
|
72
|
+
promptModules.forEach(m => m(promptAPI))
|
|
73
|
+
clearConsole()
|
|
74
|
+
|
|
75
|
+
const prompts = creator.getFinalPrompts()
|
|
76
|
+
prompts[0].choices = prompts[0].choices.map(choice => ({
|
|
77
|
+
...choice,
|
|
78
|
+
checked: false,
|
|
79
|
+
}))
|
|
80
|
+
|
|
81
|
+
const answers = await inquirer.prompt(prompts)
|
|
82
|
+
const { saveAsDefault } = await inquirer.prompt([
|
|
83
|
+
{
|
|
84
|
+
name: 'saveAsDefault',
|
|
85
|
+
type: 'confirm',
|
|
86
|
+
message: 'Save this selection as default config?',
|
|
87
|
+
default: false,
|
|
88
|
+
},
|
|
89
|
+
])
|
|
90
|
+
if (saveAsDefault) {
|
|
91
|
+
await fs.writeJson(DEFAULT_CONFIG_PATH, answers, { spaces: 2 })
|
|
92
|
+
}
|
|
93
|
+
return answers
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function detectPackageManagers() {
|
|
97
|
+
const hasNpm = await execa('npm', ['--version']).then(() => true).catch(() => false)
|
|
98
|
+
const hasYarn = await execa('yarn', ['--version']).then(() => true).catch(() => false)
|
|
99
|
+
return { npm: hasNpm, yarn: hasYarn }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function selectPackageManager() {
|
|
103
|
+
const { npm, yarn } = await detectPackageManagers()
|
|
104
|
+
|
|
105
|
+
if (npm && yarn) {
|
|
106
|
+
const { pm } = await inquirer.prompt([
|
|
107
|
+
{
|
|
108
|
+
name: 'pm',
|
|
109
|
+
type: 'list',
|
|
110
|
+
message: 'Pick a package manager:',
|
|
111
|
+
choices: [
|
|
112
|
+
{ name: 'npm', value: 'npm' },
|
|
113
|
+
{ name: 'yarn', value: 'yarn' },
|
|
114
|
+
],
|
|
115
|
+
default: 'npm',
|
|
116
|
+
},
|
|
117
|
+
])
|
|
118
|
+
return pm
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (yarn) return 'yarn'
|
|
122
|
+
if (npm) return 'npm'
|
|
123
|
+
|
|
124
|
+
throw new Error('No package manager found (npm or yarn)')
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function selectRegistry(pm) {
|
|
128
|
+
const { registry } = await inquirer.prompt([
|
|
129
|
+
{
|
|
130
|
+
name: 'registry',
|
|
131
|
+
type: 'list',
|
|
132
|
+
message: `Pick ${pm} registry:`,
|
|
133
|
+
choices: [
|
|
134
|
+
{ name: '官方源', value: 'https://registry.npmjs.org/' },
|
|
135
|
+
{ name: '淘宝源', value: 'https://registry.npmmirror.com' },
|
|
136
|
+
],
|
|
137
|
+
default: 'https://registry.npmjs.org/',
|
|
138
|
+
},
|
|
139
|
+
])
|
|
140
|
+
return registry
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function promptAutoInstall(options, pm) {
|
|
144
|
+
if (options.skipInstall === true) return
|
|
145
|
+
const { autoInstall } = await inquirer.prompt([
|
|
146
|
+
{
|
|
147
|
+
name: 'autoInstall',
|
|
148
|
+
type: 'confirm',
|
|
149
|
+
message: `Auto install dependencies with ${pm} install?`,
|
|
150
|
+
default: true,
|
|
151
|
+
},
|
|
152
|
+
])
|
|
153
|
+
options.skipInstall = !autoInstall
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function create(name, options = {}) {
|
|
157
|
+
const targetDir = path.join(process.cwd(), name)
|
|
158
|
+
const pm = await selectPackageManager()
|
|
159
|
+
const registry = await selectRegistry(pm)
|
|
160
|
+
let writeMode = 'new'
|
|
161
|
+
if (await fs.pathExists(targetDir)) {
|
|
162
|
+
const { mode } = await inquirer.prompt([
|
|
163
|
+
{
|
|
164
|
+
name: 'mode',
|
|
165
|
+
type: 'list',
|
|
166
|
+
message: `${name} already exists, what to do?`,
|
|
167
|
+
choices: [
|
|
168
|
+
{ name: 'Cancel', value: 'cancel' },
|
|
169
|
+
{ name: 'Overwrite', value: 'overwrite' },
|
|
170
|
+
{ name: 'Merge', value: 'merge' },
|
|
171
|
+
],
|
|
172
|
+
default: 'cancel',
|
|
173
|
+
},
|
|
174
|
+
])
|
|
175
|
+
if (mode === 'cancel') return
|
|
176
|
+
if (mode === 'overwrite') await fs.remove(targetDir)
|
|
177
|
+
writeMode = mode
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const { templateSource } = await inquirer.prompt([
|
|
181
|
+
{
|
|
182
|
+
name: 'templateSource',
|
|
183
|
+
type: 'list',
|
|
184
|
+
message: 'Pick a template source:',
|
|
185
|
+
choices: [
|
|
186
|
+
{ name: 'Local templates', value: 'local' },
|
|
187
|
+
{ name: 'Remote git repo', value: 'remote' },
|
|
188
|
+
],
|
|
189
|
+
default: 'local',
|
|
190
|
+
},
|
|
191
|
+
])
|
|
192
|
+
|
|
193
|
+
if (templateSource === 'remote') {
|
|
194
|
+
const { templateKey } = await inquirer.prompt([
|
|
195
|
+
{
|
|
196
|
+
name: 'templateKey',
|
|
197
|
+
type: 'list',
|
|
198
|
+
message: 'Pick a remote template:',
|
|
199
|
+
choices: REMOTE_TEMPLATES.map(t => ({ name: t.name, value: t.name })),
|
|
200
|
+
default: REMOTE_TEMPLATES[0].name,
|
|
201
|
+
},
|
|
202
|
+
])
|
|
203
|
+
|
|
204
|
+
let { repoUrl, repoBranch } = REMOTE_TEMPLATES.find(t => t.name === templateKey) || REMOTE_TEMPLATES[0]
|
|
205
|
+
|
|
206
|
+
if (templateKey === 'custom') {
|
|
207
|
+
const input = await inquirer.prompt([
|
|
208
|
+
{
|
|
209
|
+
name: 'repoUrl',
|
|
210
|
+
type: 'input',
|
|
211
|
+
message: 'Git repo url:',
|
|
212
|
+
validate: (v) => !!v || 'repo url is required',
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: 'repoBranch',
|
|
216
|
+
type: 'input',
|
|
217
|
+
message: 'Branch/tag (optional):',
|
|
218
|
+
},
|
|
219
|
+
])
|
|
220
|
+
repoUrl = input.repoUrl
|
|
221
|
+
repoBranch = input.repoBranch
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const answers = await promptFeatures()
|
|
225
|
+
|
|
226
|
+
const cloneArgs = ['clone', '--depth', '1']
|
|
227
|
+
if (repoBranch) cloneArgs.push('-b', repoBranch)
|
|
228
|
+
let cloneTarget = targetDir
|
|
229
|
+
if (writeMode === 'merge') {
|
|
230
|
+
cloneTarget = await fs.mkdtemp(path.join(os.tmpdir(), 'mvc-template-'))
|
|
231
|
+
}
|
|
232
|
+
cloneArgs.push(repoUrl, cloneTarget)
|
|
233
|
+
|
|
234
|
+
logStep(1, 3, 'Downloading remote template')
|
|
235
|
+
await execa('git', cloneArgs, { stdio: 'inherit' })
|
|
236
|
+
await fs.remove(path.join(cloneTarget, '.git'))
|
|
237
|
+
if (writeMode === 'merge') {
|
|
238
|
+
await fs.copy(cloneTarget, targetDir, {
|
|
239
|
+
overwrite: false,
|
|
240
|
+
errorOnExist: false,
|
|
241
|
+
filter: (src) => !src.includes(`${path.sep}.git${path.sep}`) && !src.endsWith(`${path.sep}.git`),
|
|
242
|
+
})
|
|
243
|
+
await fs.remove(cloneTarget)
|
|
244
|
+
}
|
|
245
|
+
logSuccess('Template downloaded')
|
|
246
|
+
|
|
247
|
+
let pkg = {
|
|
248
|
+
name,
|
|
249
|
+
version: '0.1.0',
|
|
250
|
+
dependencies: {},
|
|
251
|
+
devDependencies: {},
|
|
252
|
+
}
|
|
253
|
+
const pkgPath = path.join(targetDir, 'package.json')
|
|
254
|
+
if (await fs.pathExists(pkgPath)) {
|
|
255
|
+
pkg = await fs.readJson(pkgPath)
|
|
256
|
+
}
|
|
257
|
+
pkg.name = name
|
|
258
|
+
|
|
259
|
+
const generator = new Generator(pkg, targetDir)
|
|
260
|
+
answers.features.forEach(feature => {
|
|
261
|
+
require(`./generator/${feature}`)(generator, answers)
|
|
262
|
+
})
|
|
263
|
+
await generator.generate({ overwrite: writeMode !== 'merge' })
|
|
264
|
+
logSuccess('Plugins applied')
|
|
265
|
+
|
|
266
|
+
await promptAutoInstall(options, pm)
|
|
267
|
+
|
|
268
|
+
if (!options.skipInstall) {
|
|
269
|
+
logStep(2, 3, 'Installing dependencies')
|
|
270
|
+
await executeCommand(`${pm} install --registry=${registry}`, targetDir)
|
|
271
|
+
logSuccess('Dependencies installed')
|
|
272
|
+
} else {
|
|
273
|
+
logStep(2, 3, 'Skipped dependency install')
|
|
274
|
+
logSuccess('Dependencies skipped')
|
|
275
|
+
}
|
|
276
|
+
logStep(3, 3, 'Project ready')
|
|
277
|
+
printNextSteps(name, options.skipInstall, pm, registry)
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const answers = await promptFeatures()
|
|
282
|
+
await promptAutoInstall(options, pm)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
// package.json 文件内容
|
|
287
|
+
const pkg = {
|
|
288
|
+
name,
|
|
289
|
+
version: '0.1.0',
|
|
290
|
+
dependencies: {},
|
|
291
|
+
devDependencies: {},
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const generator = new Generator(pkg, targetDir)
|
|
295
|
+
// 填入 vue webpack 必选项,无需用户选择
|
|
296
|
+
answers.features.unshift('vue', 'webpack')
|
|
297
|
+
|
|
298
|
+
// 根据用户选择的选项加载相应的模块,在 package.json 写入对应的依赖项
|
|
299
|
+
// 并且将对应的 template 模块渲染
|
|
300
|
+
answers.features.forEach(feature => {
|
|
301
|
+
require(`./generator/${feature}`)(generator, answers)
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
await generator.generate({ overwrite: writeMode !== 'merge' })
|
|
305
|
+
logSuccess('Local template generated')
|
|
306
|
+
|
|
307
|
+
if (!options.skipInstall) {
|
|
308
|
+
logStep(2, 3, 'Installing dependencies')
|
|
309
|
+
await executeCommand(`${pm} install --registry=${registry}`, targetDir)
|
|
310
|
+
logSuccess('Dependencies installed')
|
|
311
|
+
} else {
|
|
312
|
+
logStep(2, 3, 'Skipped dependency install')
|
|
313
|
+
logSuccess('Dependencies skipped')
|
|
314
|
+
}
|
|
315
|
+
logStep(3, 3, 'Project ready')
|
|
316
|
+
printNextSteps(name, options.skipInstall, pm, registry)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function getPromptModules() {
|
|
320
|
+
return [
|
|
321
|
+
'babel',
|
|
322
|
+
'router',
|
|
323
|
+
'vuex',
|
|
324
|
+
'linter',
|
|
325
|
+
].map(file => require(`./promptModules/${file}`))
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
module.exports = create
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module.exports = (generator) => {
|
|
2
|
+
generator.extendPackage({
|
|
3
|
+
babel: {
|
|
4
|
+
presets: ['@babel/preset-env'],
|
|
5
|
+
},
|
|
6
|
+
dependencies: {
|
|
7
|
+
'core-js': '^3.8.3',
|
|
8
|
+
},
|
|
9
|
+
devDependencies: {
|
|
10
|
+
'@babel/core': '^7.12.13',
|
|
11
|
+
'@babel/preset-env': '^7.12.13',
|
|
12
|
+
'babel-loader': '^8.2.2',
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const map = {
|
|
2
|
+
airbnb: {
|
|
3
|
+
'eslint-config-airbnb-base': '^14.2.1',
|
|
4
|
+
'eslint-plugin-import': '^2.22.1',
|
|
5
|
+
},
|
|
6
|
+
standard: {
|
|
7
|
+
'eslint-config-standard': '^16.0.2',
|
|
8
|
+
'eslint-plugin-import': '^2.22.1',
|
|
9
|
+
'eslint-plugin-node': '^11.1.0',
|
|
10
|
+
'eslint-plugin-promise': '^4.3.1',
|
|
11
|
+
},
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = (generator, { lintOn, eslintConfig }) => {
|
|
15
|
+
generator.render('./template', {
|
|
16
|
+
hasAirbnb: eslintConfig == 'airbnb',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
generator.extendPackage({
|
|
20
|
+
scripts: {
|
|
21
|
+
lint: 'eslint --ext .js,.jsx,.vue src/',
|
|
22
|
+
},
|
|
23
|
+
devDependencies: {
|
|
24
|
+
'babel-eslint': '^10.1.0',
|
|
25
|
+
eslint: '^7.20.0',
|
|
26
|
+
'eslint-plugin-vue': '^7.6.0',
|
|
27
|
+
...map[eslintConfig],
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
if (lintOn.includes('commit')) {
|
|
32
|
+
generator.extendPackage({
|
|
33
|
+
devDependencies: {
|
|
34
|
+
husky: '^5.0.9',
|
|
35
|
+
'lint-staged': '^10.5.4',
|
|
36
|
+
},
|
|
37
|
+
husky: {
|
|
38
|
+
hooks: {
|
|
39
|
+
'pre-commit': 'lint-staged',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
'lint-staged': {
|
|
43
|
+
'src/**/*.{js,jsx,vue}': 'eslint --fix',
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (lintOn.includes('save')) {
|
|
49
|
+
generator.extendPackage({
|
|
50
|
+
devDependencies: {
|
|
51
|
+
'eslint-loader': '^4.0.2',
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
root: true,
|
|
3
|
+
parserOptions: {
|
|
4
|
+
ecmaVersion: 2019,
|
|
5
|
+
parser: 'babel-eslint',
|
|
6
|
+
},
|
|
7
|
+
env: {
|
|
8
|
+
browser: true,
|
|
9
|
+
node: true,
|
|
10
|
+
},
|
|
11
|
+
extends: [
|
|
12
|
+
'plugin:vue/essential',
|
|
13
|
+
<%_ if (hasAirbnb) { _%>
|
|
14
|
+
'airbnb-base',
|
|
15
|
+
<%_ } else { _%>
|
|
16
|
+
'standard',
|
|
17
|
+
<%_ } _%>
|
|
18
|
+
],
|
|
19
|
+
rules: {
|
|
20
|
+
'no-console': 'off',
|
|
21
|
+
'array-element-newline': ['error', 'consistent'],
|
|
22
|
+
indent: ['error', 4, { MemberExpression: 0, SwitchCase: 1 }],
|
|
23
|
+
quotes: ['error', 'single', { allowTemplateLiterals: true }],
|
|
24
|
+
'linebreak-style': 'off',
|
|
25
|
+
semi: ['error', 'never'],
|
|
26
|
+
'comma-dangle': 'off',
|
|
27
|
+
'import/no-unresolved': 'off',
|
|
28
|
+
'eol-last': 'off',
|
|
29
|
+
},
|
|
30
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module.exports = (generator, options = {}) => {
|
|
2
|
+
generator.injectImports(generator.entryFile, `import router from './router'`)
|
|
3
|
+
|
|
4
|
+
generator.injectRootOptions(generator.entryFile, `router`)
|
|
5
|
+
|
|
6
|
+
generator.extendPackage({
|
|
7
|
+
dependencies: {
|
|
8
|
+
'vue-router': '^3.5.1',
|
|
9
|
+
},
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
generator.render('./template', {
|
|
13
|
+
historyMode: options.historyMode,
|
|
14
|
+
hasTypeScript: false,
|
|
15
|
+
plugins: [],
|
|
16
|
+
})
|
|
17
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div id="app">
|
|
3
|
+
<div id="nav">
|
|
4
|
+
<router-link to="/">Home</router-link> |
|
|
5
|
+
<router-link to="/about">About</router-link>
|
|
6
|
+
</div>
|
|
7
|
+
<router-view />
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<style>
|
|
12
|
+
#app {
|
|
13
|
+
font-family: Avenir, Helvetica, Arial, sans-serif;
|
|
14
|
+
-webkit-font-smoothing: antialiased;
|
|
15
|
+
-moz-osx-font-smoothing: grayscale;
|
|
16
|
+
text-align: center;
|
|
17
|
+
color: #2c3e50;
|
|
18
|
+
margin-top: 60px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#nav {
|
|
22
|
+
padding: 30px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#nav a {
|
|
26
|
+
font-weight: bold;
|
|
27
|
+
color: #2c3e50;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#nav a.router-link-exact-active {
|
|
31
|
+
color: #42b983;
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import Vue from 'vue'
|
|
2
|
+
import VueRouter from 'vue-router'
|
|
3
|
+
import Home from '../views/Home.vue'
|
|
4
|
+
|
|
5
|
+
Vue.use(VueRouter)
|
|
6
|
+
|
|
7
|
+
const routes = [
|
|
8
|
+
{
|
|
9
|
+
path: '/',
|
|
10
|
+
name: 'Home',
|
|
11
|
+
component: Home
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
path: '/about',
|
|
15
|
+
name: 'About',
|
|
16
|
+
// route level code-splitting
|
|
17
|
+
// this generates a separate chunk (about.[hash].js) for this route
|
|
18
|
+
// which is lazy-loaded when the route is visited.
|
|
19
|
+
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
const router = new VueRouter({
|
|
24
|
+
<%_ if (historyMode) { _%>
|
|
25
|
+
mode: 'history',
|
|
26
|
+
<%_ } _%>
|
|
27
|
+
routes
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
export default router
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="home">
|
|
3
|
+
<img alt="Vue logo" src="../assets/logo.png" />
|
|
4
|
+
<HelloWorld msg="Welcome to Your Vue.js App" />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
// @ is an alias to /src
|
|
10
|
+
import HelloWorld from '@/components/HelloWorld.vue'
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
name: 'Home',
|
|
14
|
+
components: {
|
|
15
|
+
HelloWorld
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module.exports = (generator) => {
|
|
2
|
+
generator.render('./template')
|
|
3
|
+
|
|
4
|
+
generator.extendPackage({
|
|
5
|
+
dependencies: {
|
|
6
|
+
vue: '^2.6.12',
|
|
7
|
+
},
|
|
8
|
+
devDependencies: {
|
|
9
|
+
'vue-template-compiler': '^2.6.12',
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
generator.extendPackage({
|
|
14
|
+
browserslist: [
|
|
15
|
+
'> 1%',
|
|
16
|
+
'last 2 versions',
|
|
17
|
+
'not dead',
|
|
18
|
+
],
|
|
19
|
+
})
|
|
20
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
7
|
+
<title>
|
|
8
|
+
<%%= htmlWebpackPlugin.options.title %%>
|
|
9
|
+
</title>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<noscript>
|
|
13
|
+
<strong>We're sorry but <%%= htmlWebpackPlugin.options.title %%> doesn't work properly without JavaScript
|
|
14
|
+
enabled. Please enable it to continue.</strong>
|
|
15
|
+
</noscript>
|
|
16
|
+
<div id="app"></div>
|
|
17
|
+
<!-- built files will be auto injected -->
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div id="app">
|
|
3
|
+
<img alt="Vue logo" src="./assets/logo.png" />
|
|
4
|
+
<HelloWorld msg="Welcome to Your Vue.js App" />
|
|
5
|
+
<h1>Welcome to Your Vue.js App</h1>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
import HelloWorld from './components/HelloWorld.vue'
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
name: 'App',
|
|
14
|
+
components: {
|
|
15
|
+
HelloWorld
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<style>
|
|
21
|
+
#app {
|
|
22
|
+
font-family: Avenir, Helvetica, Arial, sans-serif;
|
|
23
|
+
-webkit-font-smoothing: antialiased;
|
|
24
|
+
-moz-osx-font-smoothing: grayscale;
|
|
25
|
+
text-align: center;
|
|
26
|
+
color: #2c3e50;
|
|
27
|
+
margin-top: 60px;
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
Binary file
|