Skip to content

Commit

Permalink
feat: support generator.js and prompts.js in preset
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Aug 8, 2018
1 parent 3c9973a commit 3b21fad
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 27 deletions.
5 changes: 5 additions & 0 deletions packages/@vue/cli/__tests__/mock-preset/generator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = (api, options) => {
api.render(files => {
files['test.js'] = options.ok ? 'true' : 'false'
})
}
5 changes: 5 additions & 0 deletions packages/@vue/cli/__tests__/mock-preset/preset.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"plugins": {
"@vue/cli-plugin-babel": {}
}
}
5 changes: 5 additions & 0 deletions packages/@vue/cli/__tests__/mock-preset/prompts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = [{
type: 'confirm',
name: 'ok',
message: 'Are you ok?'
}]
32 changes: 32 additions & 0 deletions packages/@vue/cli/__tests__/preset.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
jest.mock('inquirer')
const { expectPrompts } = require('inquirer')

const path = require('path')
const fs = require('fs-extra')
const create = require('@vue/cli/lib/create')

test('fetching local preset with prompts and generator', async () => {
const cwd = path.resolve(__dirname, '../../../test')
const name = 'test-preset'

expectPrompts([{
message: 'Are you ok',
confirm: true
}])

await create(
name,
{
force: true,
git: false,
cwd,
preset: path.resolve(__dirname, './mock-preset')
}
)

const testFile = await fs.readFile(path.resolve(cwd, name, 'test.js'), 'utf-8')
expect(testFile).toBe('true')

const pkg = require(path.resolve(cwd, name, 'package.json'))
expect(pkg.devDependencies).toHaveProperty('@vue/cli-plugin-babel')
})
23 changes: 15 additions & 8 deletions packages/@vue/cli/lib/Creator.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const EventEmitter = require('events')
const fs = require('fs-extra')
const path = require('path')
const chalk = require('chalk')
const debug = require('debug')
const execa = require('execa')
const inquirer = require('inquirer')
const EventEmitter = require('events')
const Generator = require('./Generator')
const cloneDeep = require('lodash.clonedeep')
const sortObject = require('./util/sortObject')
Expand All @@ -13,7 +13,8 @@ const { clearConsole } = require('./util/clearConsole')
const PromptModuleAPI = require('./PromptModuleAPI')
const writeFileTree = require('./util/writeFileTree')
const { formatFeatures } = require('./util/features')
const fetchRemotePreset = require('./util/fetchRemotePreset')
const loadLocalPreset = require('./util/loadLocalPreset')
const loadRemotePreset = require('./util/loadRemotePreset')
const generateReadme = require('./util/generateReadme')

const {
Expand Down Expand Up @@ -113,8 +114,13 @@ module.exports = class Creator extends EventEmitter {
}
const deps = Object.keys(preset.plugins)
deps.forEach(dep => {
pkg.devDependencies[dep] = preset.plugins[dep].version ||
if (preset.plugins[dep]._isPreset) {
return
}
pkg.devDependencies[dep] = (
preset.plugins[dep].version ||
(/^@vue/.test(dep) ? `^${latest}` : `latest`)
)
})
// write package.json
await writeFileTree(context, {
Expand Down Expand Up @@ -267,13 +273,13 @@ module.exports = class Creator extends EventEmitter {

if (name in savedPresets) {
preset = savedPresets[name]
} else if (name.endsWith('.json')) {
preset = await fs.readJson(name)
} else if (name.endsWith('.json') || /^[./\\]/.test(name)) {
preset = await loadLocalPreset(path.resolve(name))
} else if (name.includes('/')) {
logWithSpinner(`Fetching remote preset ${chalk.cyan(name)}...`)
this.emit('creation', { event: 'fetch-remote-preset' })
try {
preset = await fetchRemotePreset(name, clone)
preset = await loadRemotePreset(name, clone)
stopSpinner()
} catch (e) {
stopSpinner()
Expand Down Expand Up @@ -312,7 +318,8 @@ module.exports = class Creator extends EventEmitter {
if (options.prompts) {
const prompts = loadModule(`${id}/prompts`, this.context)
if (prompts) {
console.log(`\n${chalk.cyan(id)}`)
log()
log(`${chalk.cyan(options._isPreset ? `Preset options:` : id)}`)
options = await inquirer.prompt(prompts)
}
}
Expand Down
7 changes: 4 additions & 3 deletions packages/@vue/cli/lib/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ async function create (projectName, options) {
process.env.HTTP_PROXY = options.proxy
}

const cwd = options.cwd || process.cwd()
const inCurrent = projectName === '.'
const name = inCurrent ? path.relative('../', process.cwd()) : projectName
const targetDir = path.resolve(projectName || '.')
const name = inCurrent ? path.relative('../', cwd) : projectName
const targetDir = path.resolve(cwd, projectName || '.')

const result = validateProjectName(name)
if (!result.validForNewPackages) {
Expand Down Expand Up @@ -70,7 +71,7 @@ async function create (projectName, options) {
}

module.exports = (...args) => {
create(...args).catch(err => {
return create(...args).catch(err => {
stopSpinner(false) // do not persist
error(err)
process.exit(1)
Expand Down
13 changes: 13 additions & 0 deletions packages/@vue/cli/lib/util/loadLocalPreset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const fs = require('fs-extra')
const loadPresetFromDir = require('./loadPresetFromDir')

module.exports = async function loadLocalPreset (path) {
const stats = fs.statSync(path)
if (stats.isFile()) {
return await fs.readJson(path)
} else if (stats.isDirectory()) {
return await loadPresetFromDir(path)
} else {
throw new Error(`Invalid local preset path: ${path}`)
}
}
22 changes: 22 additions & 0 deletions packages/@vue/cli/lib/util/loadPresetFromDir.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const path = require('path')
const fs = require('fs-extra')

module.exports = async function loadPresetFromDir (dir) {
const presetPath = path.join(dir, 'preset.json')
if (!fs.existsSync(presetPath)) {
throw new Error('remote / local preset does not contain preset.json!')
}
const preset = await fs.readJson(presetPath)

// if the preset dir contains generator.js, we will inject it as a hidden
// plugin so it will be invoked by the generator.
const generatorPath = path.join(dir, 'generator.js')
if (fs.existsSync(generatorPath)) {
(preset.plugins || (preset.plugins = {}))[dir.replace(/[\/]$/, '')] = {
_isPreset: true,
prompts: true
}
}

return preset
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
const fs = require('fs-extra')
const loadPresetFromDir = require('./loadPresetFromDir')

module.exports = async function fetchRemotePreset (name, clone) {
// github shorthand fastpath
if (!clone && /^[\w_-]+\/[\w_-]+$/.test(name)) {
const { request } = require('@vue/cli-shared-utils')
return request.get(`https://raw.githubusercontent.com/${name}/master/preset.json`)
.then(res => res.body)
}

// fallback to full download
const os = require('os')
const path = require('path')
const download = require('download-git-repo')
Expand All @@ -20,16 +13,12 @@ module.exports = async function fetchRemotePreset (name, clone) {
await fs.remove(tmpdir)
}

return new Promise((resolve, reject) => {
await new Promise((resolve, reject) => {
download(name, tmpdir, { clone }, err => {
if (err) return reject(err)
let preset
try {
preset = require(path.join(tmpdir, 'preset.json'))
} catch (e) {
return reject(e)
}
resolve(preset)
resolve()
})
})

return await loadPresetFromDir(tmpdir)
}

0 comments on commit 3b21fad

Please sign in to comment.