Skip to content

Commit 3b21fad

Browse files
committed
feat: support generator.js and prompts.js in preset
1 parent 3c9973a commit 3b21fad

File tree

9 files changed

+106
-27
lines changed

9 files changed

+106
-27
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = (api, options) => {
2+
api.render(files => {
3+
files['test.js'] = options.ok ? 'true' : 'false'
4+
})
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"plugins": {
3+
"@vue/cli-plugin-babel": {}
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = [{
2+
type: 'confirm',
3+
name: 'ok',
4+
message: 'Are you ok?'
5+
}]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
jest.mock('inquirer')
2+
const { expectPrompts } = require('inquirer')
3+
4+
const path = require('path')
5+
const fs = require('fs-extra')
6+
const create = require('@vue/cli/lib/create')
7+
8+
test('fetching local preset with prompts and generator', async () => {
9+
const cwd = path.resolve(__dirname, '../../../test')
10+
const name = 'test-preset'
11+
12+
expectPrompts([{
13+
message: 'Are you ok',
14+
confirm: true
15+
}])
16+
17+
await create(
18+
name,
19+
{
20+
force: true,
21+
git: false,
22+
cwd,
23+
preset: path.resolve(__dirname, './mock-preset')
24+
}
25+
)
26+
27+
const testFile = await fs.readFile(path.resolve(cwd, name, 'test.js'), 'utf-8')
28+
expect(testFile).toBe('true')
29+
30+
const pkg = require(path.resolve(cwd, name, 'package.json'))
31+
expect(pkg.devDependencies).toHaveProperty('@vue/cli-plugin-babel')
32+
})

packages/@vue/cli/lib/Creator.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
const EventEmitter = require('events')
2-
const fs = require('fs-extra')
1+
const path = require('path')
32
const chalk = require('chalk')
43
const debug = require('debug')
54
const execa = require('execa')
65
const inquirer = require('inquirer')
6+
const EventEmitter = require('events')
77
const Generator = require('./Generator')
88
const cloneDeep = require('lodash.clonedeep')
99
const sortObject = require('./util/sortObject')
@@ -13,7 +13,8 @@ const { clearConsole } = require('./util/clearConsole')
1313
const PromptModuleAPI = require('./PromptModuleAPI')
1414
const writeFileTree = require('./util/writeFileTree')
1515
const { formatFeatures } = require('./util/features')
16-
const fetchRemotePreset = require('./util/fetchRemotePreset')
16+
const loadLocalPreset = require('./util/loadLocalPreset')
17+
const loadRemotePreset = require('./util/loadRemotePreset')
1718
const generateReadme = require('./util/generateReadme')
1819

1920
const {
@@ -113,8 +114,13 @@ module.exports = class Creator extends EventEmitter {
113114
}
114115
const deps = Object.keys(preset.plugins)
115116
deps.forEach(dep => {
116-
pkg.devDependencies[dep] = preset.plugins[dep].version ||
117+
if (preset.plugins[dep]._isPreset) {
118+
return
119+
}
120+
pkg.devDependencies[dep] = (
121+
preset.plugins[dep].version ||
117122
(/^@vue/.test(dep) ? `^${latest}` : `latest`)
123+
)
118124
})
119125
// write package.json
120126
await writeFileTree(context, {
@@ -267,13 +273,13 @@ module.exports = class Creator extends EventEmitter {
267273

268274
if (name in savedPresets) {
269275
preset = savedPresets[name]
270-
} else if (name.endsWith('.json')) {
271-
preset = await fs.readJson(name)
276+
} else if (name.endsWith('.json') || /^[./\\]/.test(name)) {
277+
preset = await loadLocalPreset(path.resolve(name))
272278
} else if (name.includes('/')) {
273279
logWithSpinner(`Fetching remote preset ${chalk.cyan(name)}...`)
274280
this.emit('creation', { event: 'fetch-remote-preset' })
275281
try {
276-
preset = await fetchRemotePreset(name, clone)
282+
preset = await loadRemotePreset(name, clone)
277283
stopSpinner()
278284
} catch (e) {
279285
stopSpinner()
@@ -312,7 +318,8 @@ module.exports = class Creator extends EventEmitter {
312318
if (options.prompts) {
313319
const prompts = loadModule(`${id}/prompts`, this.context)
314320
if (prompts) {
315-
console.log(`\n${chalk.cyan(id)}`)
321+
log()
322+
log(`${chalk.cyan(options._isPreset ? `Preset options:` : id)}`)
316323
options = await inquirer.prompt(prompts)
317324
}
318325
}

packages/@vue/cli/lib/create.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ async function create (projectName, options) {
1313
process.env.HTTP_PROXY = options.proxy
1414
}
1515

16+
const cwd = options.cwd || process.cwd()
1617
const inCurrent = projectName === '.'
17-
const name = inCurrent ? path.relative('../', process.cwd()) : projectName
18-
const targetDir = path.resolve(projectName || '.')
18+
const name = inCurrent ? path.relative('../', cwd) : projectName
19+
const targetDir = path.resolve(cwd, projectName || '.')
1920

2021
const result = validateProjectName(name)
2122
if (!result.validForNewPackages) {
@@ -70,7 +71,7 @@ async function create (projectName, options) {
7071
}
7172

7273
module.exports = (...args) => {
73-
create(...args).catch(err => {
74+
return create(...args).catch(err => {
7475
stopSpinner(false) // do not persist
7576
error(err)
7677
process.exit(1)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const fs = require('fs-extra')
2+
const loadPresetFromDir = require('./loadPresetFromDir')
3+
4+
module.exports = async function loadLocalPreset (path) {
5+
const stats = fs.statSync(path)
6+
if (stats.isFile()) {
7+
return await fs.readJson(path)
8+
} else if (stats.isDirectory()) {
9+
return await loadPresetFromDir(path)
10+
} else {
11+
throw new Error(`Invalid local preset path: ${path}`)
12+
}
13+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const path = require('path')
2+
const fs = require('fs-extra')
3+
4+
module.exports = async function loadPresetFromDir (dir) {
5+
const presetPath = path.join(dir, 'preset.json')
6+
if (!fs.existsSync(presetPath)) {
7+
throw new Error('remote / local preset does not contain preset.json!')
8+
}
9+
const preset = await fs.readJson(presetPath)
10+
11+
// if the preset dir contains generator.js, we will inject it as a hidden
12+
// plugin so it will be invoked by the generator.
13+
const generatorPath = path.join(dir, 'generator.js')
14+
if (fs.existsSync(generatorPath)) {
15+
(preset.plugins || (preset.plugins = {}))[dir.replace(/[\/]$/, '')] = {
16+
_isPreset: true,
17+
prompts: true
18+
}
19+
}
20+
21+
return preset
22+
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
const fs = require('fs-extra')
2+
const loadPresetFromDir = require('./loadPresetFromDir')
23

34
module.exports = async function fetchRemotePreset (name, clone) {
4-
// github shorthand fastpath
5-
if (!clone && /^[\w_-]+\/[\w_-]+$/.test(name)) {
6-
const { request } = require('@vue/cli-shared-utils')
7-
return request.get(`https://raw.githubusercontent.com/${name}/master/preset.json`)
8-
.then(res => res.body)
9-
}
10-
11-
// fallback to full download
125
const os = require('os')
136
const path = require('path')
147
const download = require('download-git-repo')
@@ -20,16 +13,12 @@ module.exports = async function fetchRemotePreset (name, clone) {
2013
await fs.remove(tmpdir)
2114
}
2215

23-
return new Promise((resolve, reject) => {
16+
await new Promise((resolve, reject) => {
2417
download(name, tmpdir, { clone }, err => {
2518
if (err) return reject(err)
26-
let preset
27-
try {
28-
preset = require(path.join(tmpdir, 'preset.json'))
29-
} catch (e) {
30-
return reject(e)
31-
}
32-
resolve(preset)
19+
resolve()
3320
})
3421
})
22+
23+
return await loadPresetFromDir(tmpdir)
3524
}

0 commit comments

Comments
 (0)