mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-03-13 12:40:18 -05:00
refactor: adjust generation strategy
This commit is contained in:
10
packages/@vue/cli-plugin-babel/generator.js
Normal file
10
packages/@vue/cli-plugin-babel/generator.js
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = api => {
|
||||
api.extendPackage({
|
||||
devDependencies: {
|
||||
'babel-preset-vue-app': '^2.0.0'
|
||||
},
|
||||
babel: {
|
||||
presets: ['vue-app'] // TODO update babel-preset-vue-app
|
||||
}
|
||||
})
|
||||
}
|
||||
3
packages/@vue/cli-plugin-eslint/generator.js
Normal file
3
packages/@vue/cli-plugin-eslint/generator.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (api, options) => {
|
||||
|
||||
}
|
||||
3
packages/@vue/cli-plugin-eslint/index.js
Normal file
3
packages/@vue/cli-plugin-eslint/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (api, options) => {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { shallow } from 'vue-test-utils'
|
||||
import HelloWorld from '@/components/HelloWorld.vue'
|
||||
|
||||
describe('Hello.vue', () => {
|
||||
it('renders props.msg when passed', () => {
|
||||
const msg = 'new message'
|
||||
const wrapper = shallow(HelloWorld, {
|
||||
context: { props: { msg } }
|
||||
})
|
||||
expect(wrapper.text()).toBe(msg)
|
||||
})
|
||||
})
|
||||
@@ -5,7 +5,6 @@ module.exports = (api, options) => {
|
||||
test: 'jest'
|
||||
},
|
||||
devDependencies: {
|
||||
'@vue/cli-plugin-unit-jest': '^0.1.0',
|
||||
'jest': '^22.0.4',
|
||||
'vue-test-utils': '^1.0.0-beta.9'
|
||||
},
|
||||
@@ -1,5 +1,5 @@
|
||||
import { shallow } from 'vue-test-utils'
|
||||
<%_ if (options.assertionLibrary === 'expect' && options.unit !== 'jest') { _%>
|
||||
<%_ if (options.assertionLibrary === 'expect') { _%>
|
||||
import { expect } from 'expect'
|
||||
<%_ } _%>
|
||||
<%_ if (options.assertionLibrary === 'chai') { _%>
|
||||
@@ -13,7 +13,7 @@ describe('Hello.vue', () => {
|
||||
const wrapper = shallow(HelloWorld, {
|
||||
context: { props: { msg } }
|
||||
})
|
||||
<%_ if (options.assertionLibrary === 'expect' || options.unit === 'jest') { _%>
|
||||
<%_ if (options.assertionLibrary === 'expect') { _%>
|
||||
expect(wrapper.text()).toBe(msg)
|
||||
<%_ } else if (options.assertionLibrary === 'chai') { _%>
|
||||
expect(wrapper.text()).to.equal(msg)
|
||||
@@ -1,6 +1,7 @@
|
||||
module.exports = (api, options) => {
|
||||
api.renderFiles('./files')
|
||||
|
||||
const devDependencies = {
|
||||
'@vue/cli-plugin-unit-mocha-webpack': '^0.1.0',
|
||||
'vue-test-utils': '^1.0.0-beta.9'
|
||||
}
|
||||
if (options.assertionLibrary === 'chai') {
|
||||
@@ -15,6 +16,4 @@ module.exports = (api, options) => {
|
||||
test: 'vue-cli-service test'
|
||||
}
|
||||
})
|
||||
|
||||
api.renderFiles('./files')
|
||||
}
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
const semver = require('semver')
|
||||
const { error } = require('@vue/cli-shared-utils')
|
||||
const requiredVersion = require('../package.json').engine.node
|
||||
const requiredVersion = require('../package.json').engines.node
|
||||
|
||||
if (!semver.satisfies(process.version, requiredVersion)) {
|
||||
error(
|
||||
`You are using Node ${process.version}, but vue-cli-service\n` +
|
||||
`requires Node ${requiredVersion}. Please upgrade your Node version.`
|
||||
`You are using Node ${process.version}, but vue-cli-service ` +
|
||||
`requires Node ${requiredVersion}.\nPlease upgrade your Node version.`
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
32
packages/@vue/cli-service/generator/index.js
Normal file
32
packages/@vue/cli-service/generator/index.js
Normal file
@@ -0,0 +1,32 @@
|
||||
module.exports = (generatorAPI, options) => {
|
||||
generatorAPI.renderFiles('./files')
|
||||
generatorAPI.extendPackage({
|
||||
scripts: {
|
||||
'dev': 'vue-cli-service serve' + (
|
||||
// only auto open browser on MacOS where applescript
|
||||
// can avoid dupilcate window opens
|
||||
process.platform === 'darwin'
|
||||
? ' --open'
|
||||
: ''
|
||||
),
|
||||
'build': 'vue-cli-service build',
|
||||
'start': 'vue-cli-service serve --prod'
|
||||
},
|
||||
dependencies: {
|
||||
'vue': '^2.5.13'
|
||||
},
|
||||
devDependencies: {
|
||||
'vue-template-compiler': '^2.5.13'
|
||||
},
|
||||
'postcss': {
|
||||
'plugins': {
|
||||
'autoprefixer': {}
|
||||
}
|
||||
},
|
||||
browserslist: [
|
||||
'> 1%',
|
||||
'last 2 versions',
|
||||
'not ie <= 8'
|
||||
]
|
||||
})
|
||||
}
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
const semver = require('semver')
|
||||
const { error } = require('@vue/cli-shared-utils')
|
||||
const requiredVersion = require('../package.json').engine.node
|
||||
const requiredVersion = require('../package.json').engines.node
|
||||
|
||||
if (!semver.satisfies(process.version, requiredVersion)) {
|
||||
error(
|
||||
`You are using Node ${process.version}, but this version of vue-cli\n` +
|
||||
`requires Node ${requiredVersion}. Please upgrade your Node version.`
|
||||
`You are using Node ${process.version}, but this version of vue-cli ` +
|
||||
`requires Node ${requiredVersion}.\nPlease upgrade your Node version.`
|
||||
)
|
||||
process.exit(1)
|
||||
} else {
|
||||
|
||||
@@ -1,106 +1,115 @@
|
||||
const fs = require('fs')
|
||||
const os = require('os')
|
||||
const ejs = require('ejs')
|
||||
const path = require('path')
|
||||
const chalk = require('chalk')
|
||||
const debug = require('debug')
|
||||
const inquirer = require('inquirer')
|
||||
const GeneratorAPI = require('./GeneratorAPI')
|
||||
const Generator = require('./Generator')
|
||||
const installDeps = require('./util/installDeps')
|
||||
const PromptModuleAPI = require('./PromptModuleAPI')
|
||||
const writeFileTree = require('./util/writeFileTree')
|
||||
|
||||
const {
|
||||
info,
|
||||
error,
|
||||
success,
|
||||
hasYarn,
|
||||
clearConsole
|
||||
} = require('@vue/cli-shared-utils')
|
||||
|
||||
const debug = require('debug')
|
||||
const rcPath = path.join(os.homedir(), '.vuerc')
|
||||
const isMode = _mode => ({ mode }) => _mode === mode
|
||||
|
||||
const defaultOptions = {
|
||||
features: ['eslint', 'unit'],
|
||||
eslint: 'eslint-only',
|
||||
unit: 'mocha',
|
||||
assertionLibrary: 'chai',
|
||||
packageManager: hasYarn ? 'yarn' : 'npm'
|
||||
packageManager: hasYarn ? 'yarn' : 'npm',
|
||||
plugins: {
|
||||
'@vue/cli-plugin-babel': {},
|
||||
'@vue/cli-plugin-eslint': { config: 'eslint-only' },
|
||||
'@vue/cli-plugin-unit-mocha-webpack': { assertionLibrary: 'chai' }
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = class Creator {
|
||||
constructor (name, generators) {
|
||||
this.name = name
|
||||
constructor (modules) {
|
||||
const { modePrompt, featurePrompt } = this.resolveIntroPrompts()
|
||||
this.modePrompt = modePrompt
|
||||
this.featurePrompt = featurePrompt
|
||||
this.outroPrompts = this.resolveOutroPrompts()
|
||||
this.injectedPrompts = []
|
||||
this.promptCompleteCbs = []
|
||||
this.fileMiddlewares = []
|
||||
|
||||
this.options = {}
|
||||
this.pkg = {
|
||||
name,
|
||||
version: '0.1.0',
|
||||
private: true,
|
||||
scripts: {},
|
||||
dependencies: {},
|
||||
devDependencies: {}
|
||||
}
|
||||
// for conflict resolution
|
||||
this.depSources = {}
|
||||
// virtual file tree
|
||||
this.files = {}
|
||||
|
||||
generators.forEach(({ id, apply }) => {
|
||||
apply(new GeneratorAPI(id, this))
|
||||
})
|
||||
const api = new PromptModuleAPI(this)
|
||||
modules.forEach(m => m(api))
|
||||
}
|
||||
|
||||
async create (targetDir) {
|
||||
async create (name, targetDir) {
|
||||
// prompt
|
||||
clearConsole()
|
||||
let options = await inquirer.prompt(this.resolveFinalPrompts())
|
||||
debug('rawOptions')(options)
|
||||
const answers = await inquirer.prompt(this.resolveFinalPrompts())
|
||||
debug('answers')(answers)
|
||||
|
||||
if (options.mode === 'saved') {
|
||||
let options
|
||||
if (answers.mode === 'saved') {
|
||||
options = this.loadSavedOptions()
|
||||
} else if (options.mode === 'default') {
|
||||
} else if (answers.mode === 'default') {
|
||||
options = defaultOptions
|
||||
} else {
|
||||
options = {
|
||||
packageManager: answers.packageManager,
|
||||
plugins: {}
|
||||
}
|
||||
}
|
||||
options.projectName = this.name
|
||||
|
||||
// run cb registered by generators
|
||||
this.promptCompleteCbs.forEach(cb => cb(options))
|
||||
this.options = options
|
||||
debug('options')(options)
|
||||
// run cb registered by prompt modules to finalize the options
|
||||
this.promptCompleteCbs.forEach(cb => cb(answers, options))
|
||||
|
||||
// save options
|
||||
if (options.mode === 'manual' && options.save) {
|
||||
if (answers.mode === 'manual' && answers.save) {
|
||||
this.saveOptions(options)
|
||||
}
|
||||
|
||||
// wait for file resolve
|
||||
await this.resolveFiles()
|
||||
// set package.json
|
||||
this.resolvePkg()
|
||||
this.files['package.json'] = JSON.stringify(this.pkg, null, 2)
|
||||
// write file tree to disk
|
||||
await writeFileTree(targetDir, this.files)
|
||||
|
||||
success(`Project created in ${chalk.cyan(options.projectName)}.`)
|
||||
|
||||
if (options.packageManager) {
|
||||
info(`Installing dependencies with ${options.packageManager}. This may take a while...`)
|
||||
await installDeps(options.packageManager, targetDir)
|
||||
// inject core service
|
||||
options.plugins['@vue/cli-service'] = {
|
||||
projectName: name
|
||||
}
|
||||
|
||||
debug('options')(options)
|
||||
|
||||
// write base package.json to disk
|
||||
info(`Creating project in ${chalk.cyan(targetDir)}.`)
|
||||
writeFileTree(targetDir, {
|
||||
'package.json': JSON.stringify({
|
||||
name,
|
||||
version: '0.1.0',
|
||||
private: true
|
||||
}, null, 2)
|
||||
})
|
||||
|
||||
// install deps
|
||||
info(`Installing dependencies with ${options.packageManager}. This may take a while...`)
|
||||
const deps = Object.keys(options.plugins)
|
||||
if (process.env.VUE_CLI_DEBUG) {
|
||||
// in development, use linked packages
|
||||
updatePackageForDev(targetDir, deps)
|
||||
await installDeps(options.packageManager, targetDir)
|
||||
} else {
|
||||
await installDeps(options.packageManager, targetDir, deps)
|
||||
}
|
||||
|
||||
// run generator
|
||||
const generator = new Generator(targetDir, options)
|
||||
await generator.generate()
|
||||
|
||||
// install deps again (new deps injected by generators)
|
||||
await installDeps(options.packageManager, targetDir)
|
||||
|
||||
// TODO run vue-cli-service init
|
||||
}
|
||||
|
||||
resolveIntroPrompts () {
|
||||
const modePrompt = {
|
||||
name: 'mode',
|
||||
type: 'list',
|
||||
message: `Pick a project creation mode:`,
|
||||
message: `Hi there! Please pick a project creation mode:`,
|
||||
choices: [
|
||||
{
|
||||
name: 'Zero-configuration with defaults',
|
||||
@@ -122,7 +131,7 @@ module.exports = class Creator {
|
||||
name: 'features',
|
||||
when: isMode('manual'),
|
||||
type: 'checkbox',
|
||||
message: 'Please check the features needed for your project.',
|
||||
message: 'Check the features needed for your project:',
|
||||
choices: []
|
||||
}
|
||||
return {
|
||||
@@ -132,46 +141,33 @@ module.exports = class Creator {
|
||||
}
|
||||
|
||||
resolveOutroPrompts () {
|
||||
const outroPrompts = [
|
||||
{
|
||||
name: 'save',
|
||||
when: isMode('manual'),
|
||||
type: 'confirm',
|
||||
message: 'Save the preferences for future projects?'
|
||||
}
|
||||
]
|
||||
const outroPrompts = []
|
||||
if (hasYarn) {
|
||||
outroPrompts.unshift({
|
||||
outroPrompts.push({
|
||||
name: 'packageManager',
|
||||
when: isMode('manual'),
|
||||
type: 'list',
|
||||
message: 'Automatically install NPM dependencies after project creation?',
|
||||
message: 'Pick the package manager to use when installing dependencies:',
|
||||
choices: [
|
||||
{
|
||||
name: 'Use NPM',
|
||||
value: 'npm',
|
||||
short: 'NPM'
|
||||
},
|
||||
{
|
||||
name: 'Use Yarn',
|
||||
value: 'yarn',
|
||||
short: 'Yarn'
|
||||
},
|
||||
{
|
||||
name: `I'll handle that myself`,
|
||||
value: false,
|
||||
short: 'No'
|
||||
name: 'Use NPM',
|
||||
value: 'npm',
|
||||
short: 'NPM'
|
||||
}
|
||||
]
|
||||
})
|
||||
} else {
|
||||
outroPrompts.unshift({
|
||||
name: 'packageManager',
|
||||
when: isMode('manual'),
|
||||
type: 'confirm',
|
||||
message: 'Automatically install NPM dependencies after project creation?'
|
||||
})
|
||||
}
|
||||
outroPrompts.push({
|
||||
name: 'save',
|
||||
when: isMode('manual'),
|
||||
type: 'confirm',
|
||||
message: 'Save the preferences for future projects?'
|
||||
})
|
||||
return outroPrompts
|
||||
}
|
||||
|
||||
@@ -208,6 +204,10 @@ module.exports = class Creator {
|
||||
}
|
||||
|
||||
saveOptions (options) {
|
||||
options = Object.assign({}, options)
|
||||
delete options.projectName
|
||||
delete options.mode
|
||||
delete options.save
|
||||
try {
|
||||
fs.writeFileSync(rcPath, JSON.stringify(options, null, 2))
|
||||
} catch (e) {
|
||||
@@ -218,21 +218,21 @@ module.exports = class Creator {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
resolvePkg () {
|
||||
const sortDeps = deps => Object.keys(deps).sort().reduce((res, name) => {
|
||||
res[name] = deps[name]
|
||||
return res
|
||||
}, {})
|
||||
this.pkg.dependencies = sortDeps(this.pkg.dependencies)
|
||||
this.pkg.devDependencies = sortDeps(this.pkg.devDependencies)
|
||||
debug('pkg')(this.pkg)
|
||||
}
|
||||
|
||||
async resolveFiles () {
|
||||
for (const middleware of this.fileMiddlewares) {
|
||||
await middleware(this.files, ejs.render)
|
||||
}
|
||||
debug('files')(this.files)
|
||||
}
|
||||
}
|
||||
|
||||
function updatePackageForDev (targetDir, deps) {
|
||||
const pkg = require(path.resolve(targetDir, 'package.json'))
|
||||
pkg.devDependencies = {}
|
||||
deps.forEach(dep => {
|
||||
pkg.devDependencies[dep] = require(path.resolve(
|
||||
__dirname,
|
||||
'../../../',
|
||||
dep,
|
||||
'package.json'
|
||||
)).version
|
||||
})
|
||||
fs.writeFileSync(
|
||||
path.resolve(targetDir, 'package.json'),
|
||||
JSON.stringify(pkg, null, 2)
|
||||
)
|
||||
}
|
||||
|
||||
56
packages/@vue/cli/lib/Generator.js
Normal file
56
packages/@vue/cli/lib/Generator.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const ejs = require('ejs')
|
||||
const path = require('path')
|
||||
const debug = require('debug')
|
||||
const resolve = require('resolve')
|
||||
const GeneratorAPI = require('./GeneratorAPI')
|
||||
const { success } = require('@vue/cli-shared-utils')
|
||||
const writeFileTree = require('./util/writeFileTree')
|
||||
|
||||
module.exports = class Generator {
|
||||
constructor (context, options) {
|
||||
this.context = context
|
||||
this.options = options
|
||||
this.pkg = require(path.resolve(context, 'package.json'))
|
||||
// for conflict resolution
|
||||
this.depSources = {}
|
||||
// virtual file tree
|
||||
this.files = {}
|
||||
this.fileMiddlewares = []
|
||||
|
||||
// apply generators from plugins
|
||||
Object.keys(options.plugins).forEach(id => {
|
||||
const generatorPath = resolve.sync(`${id}/generator`, { basedir: context })
|
||||
const generator = require(generatorPath)
|
||||
const generatorOptions = options.plugins[id]
|
||||
generator(new GeneratorAPI(id, this, generatorOptions), generatorOptions)
|
||||
})
|
||||
}
|
||||
|
||||
async generate () {
|
||||
// wait for file resolve
|
||||
await this.resolveFiles()
|
||||
// set package.json
|
||||
this.resolvePkg()
|
||||
this.files['package.json'] = JSON.stringify(this.pkg, null, 2)
|
||||
// write file tree to disk
|
||||
await writeFileTree(this.context, this.files)
|
||||
success(`Successfully generated project files.`)
|
||||
}
|
||||
|
||||
resolvePkg () {
|
||||
const sortDeps = deps => Object.keys(deps).sort().reduce((res, name) => {
|
||||
res[name] = deps[name]
|
||||
return res
|
||||
}, {})
|
||||
this.pkg.dependencies = sortDeps(this.pkg.dependencies)
|
||||
this.pkg.devDependencies = sortDeps(this.pkg.devDependencies)
|
||||
debug('pkg')(this.pkg)
|
||||
}
|
||||
|
||||
async resolveFiles () {
|
||||
for (const middleware of this.fileMiddlewares) {
|
||||
await middleware(this.files, ejs.render)
|
||||
}
|
||||
debug('files')(this.files)
|
||||
}
|
||||
}
|
||||
@@ -5,54 +5,24 @@ const walk = require('klaw-sync')
|
||||
const isBinary = require('isbinaryfile')
|
||||
const mergeDeps = require('./util/mergeDeps')
|
||||
const errorParser = require('error-stack-parser')
|
||||
const { error } = require('@vue/cli-shared-utils')
|
||||
|
||||
const isString = val => typeof val === 'string'
|
||||
const isFunction = val => typeof val === 'function'
|
||||
const isObject = val => val && typeof val === 'object'
|
||||
|
||||
module.exports = class GeneratorAPI {
|
||||
constructor (id, creator) {
|
||||
constructor (id, generator, options) {
|
||||
this.id = id
|
||||
this.creator = creator
|
||||
}
|
||||
|
||||
injectFeature (feature) {
|
||||
this.creator.featurePrompt.choices.push(feature)
|
||||
}
|
||||
|
||||
injectPrompt (prompt) {
|
||||
this.creator.injectedPrompts.push(prompt)
|
||||
}
|
||||
|
||||
injectOptionForPrompt (name, option) {
|
||||
const prompt = this.creator.injectedPrompts.find(f => {
|
||||
return f.name === name
|
||||
})
|
||||
if (!prompt) {
|
||||
error(
|
||||
`injectOptionForFeature error in generator "${
|
||||
this.id
|
||||
}": prompt "${name}" does not exist.`
|
||||
)
|
||||
}
|
||||
prompt.choices.push(option)
|
||||
}
|
||||
|
||||
onPromptComplete (cb) {
|
||||
this.creator.promptCompleteCbs.push(cb)
|
||||
}
|
||||
|
||||
onCreateComplete (cb) {
|
||||
this.creator.onCreateCompleteCbs.push(cb)
|
||||
this.generator = generator
|
||||
this.options = options
|
||||
}
|
||||
|
||||
injectFileMiddleware (middleware) {
|
||||
this.creator.fileMiddlewares.push(middleware)
|
||||
this.generator.fileMiddlewares.push(middleware)
|
||||
}
|
||||
|
||||
extendPackage (fields, options = { merge: true }) {
|
||||
const pkg = this.creator.pkg
|
||||
const pkg = this.generator.pkg
|
||||
const toMerge = isFunction(fields) ? fields(pkg) : fields
|
||||
for (const key in toMerge) {
|
||||
if (!options.merge || !(key in pkg)) {
|
||||
@@ -69,7 +39,7 @@ module.exports = class GeneratorAPI {
|
||||
this.id,
|
||||
existing,
|
||||
value,
|
||||
this.creator.depSources
|
||||
this.generator.depSources
|
||||
)
|
||||
} else {
|
||||
pkg[key] = Object.assign({}, existing, value)
|
||||
@@ -87,7 +57,7 @@ module.exports = class GeneratorAPI {
|
||||
fileDir = path.resolve(baseDir, fileDir)
|
||||
this.injectFileMiddleware(files => {
|
||||
const data = Object.assign({
|
||||
options: this.creator.options
|
||||
options: this.options
|
||||
}, additionalData)
|
||||
const _files = walk(fileDir, {
|
||||
nodir: true,
|
||||
@@ -101,7 +71,7 @@ module.exports = class GeneratorAPI {
|
||||
} else if (isObject(fileDir)) {
|
||||
this.injectFileMiddleware(files => {
|
||||
const data = Object.assign({
|
||||
options: this.creator.options
|
||||
options: this.options
|
||||
}, additionalData)
|
||||
for (const targetPath in fileDir) {
|
||||
const sourcePath = path.resolve(baseDir, fileDir[targetPath])
|
||||
|
||||
23
packages/@vue/cli/lib/PromptModuleAPI.js
Normal file
23
packages/@vue/cli/lib/PromptModuleAPI.js
Normal file
@@ -0,0 +1,23 @@
|
||||
module.exports = class PromptModuleAPI {
|
||||
constructor (creator) {
|
||||
this.creator = creator
|
||||
}
|
||||
|
||||
injectFeature (feature) {
|
||||
this.creator.featurePrompt.choices.push(feature)
|
||||
}
|
||||
|
||||
injectPrompt (prompt) {
|
||||
this.creator.injectedPrompts.push(prompt)
|
||||
}
|
||||
|
||||
injectOptionForPrompt (name, option) {
|
||||
this.creator.injectedPrompts.find(f => {
|
||||
return f.name === name
|
||||
}).choices.push(option)
|
||||
}
|
||||
|
||||
onPromptComplete (cb) {
|
||||
this.creator.promptCompleteCbs.push(cb)
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,7 @@ const rimraf = require('rimraf')
|
||||
const inquirer = require('inquirer')
|
||||
const program = require('commander')
|
||||
const Creator = require('./Creator')
|
||||
const debug = require('debug')('create')
|
||||
const { warn, error } = require('@vue/cli-shared-utils')
|
||||
const resolveInstalledGenerators = require('./util/resolveInstalledGenerators')
|
||||
const { warn, error, clearConsole } = require('@vue/cli-shared-utils')
|
||||
|
||||
async function run () {
|
||||
program
|
||||
@@ -23,39 +21,33 @@ async function run () {
|
||||
|
||||
const targetDir = path.resolve(process.cwd(), projectName)
|
||||
if (fs.existsSync(targetDir)) {
|
||||
const { overwrite } = await inquirer.prompt([
|
||||
clearConsole()
|
||||
const { action } = await inquirer.prompt([
|
||||
{
|
||||
name: 'overwrite',
|
||||
type: 'confirm',
|
||||
message: `Target directory ${chalk.cyan(targetDir)} already exists.\n Overwrite?`
|
||||
name: 'action',
|
||||
type: 'list',
|
||||
message: `Target directory ${chalk.cyan(targetDir)} already exists. Pick an action:`,
|
||||
choices: [
|
||||
{ name: 'Overwrite', value: 'overwrite' },
|
||||
{ name: 'Merge', value: 'merge' },
|
||||
{ name: 'Cancel', value: false }
|
||||
]
|
||||
}
|
||||
])
|
||||
if (overwrite) {
|
||||
rimraf.sync(targetDir)
|
||||
} else {
|
||||
if (!action) {
|
||||
return
|
||||
} else if (action === 'overwrite') {
|
||||
rimraf.sync(targetDir)
|
||||
}
|
||||
}
|
||||
|
||||
const createGenerator = (id, requirePath = id) => ({
|
||||
id,
|
||||
apply: require(requirePath)
|
||||
})
|
||||
const promptModules = fs
|
||||
.readdirSync(path.resolve(__dirname, './promptModules'))
|
||||
.filter(file => file.charAt(0) !== '.')
|
||||
.map(file => require(`./promptModules/${file}`))
|
||||
|
||||
const builtInGenerators = fs
|
||||
.readdirSync(path.resolve(__dirname, './generators'))
|
||||
.filter(dir => dir.charAt(0) !== '.')
|
||||
.map(id => createGenerator(id, `./generators/${id}`))
|
||||
|
||||
debug(builtInGenerators)
|
||||
|
||||
const installedGenerators = resolveInstalledGenerators().map(id => {
|
||||
return createGenerator(id)
|
||||
})
|
||||
|
||||
const creator = new Creator(projectName, builtInGenerators.concat(installedGenerators))
|
||||
|
||||
await creator.create(targetDir)
|
||||
const creator = new Creator(promptModules)
|
||||
await creator.create(projectName, targetDir)
|
||||
}
|
||||
|
||||
run().catch(error)
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
module.exports = api => {
|
||||
api.onPromptComplete(options => {
|
||||
if (!options.features.includes('ts') && !options.features.includes('-babel')) {
|
||||
api.extendPackage({
|
||||
devDependencies: {
|
||||
'@vue/cli-plugin-babel': '^0.1.0',
|
||||
'babel-preset-vue-app': '^2.0.0'
|
||||
},
|
||||
babel: {
|
||||
presets: ['vue-app'] // TODO update babel-preset-vue-app
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
module.exports = api => {
|
||||
api.onPromptComplete(options => {
|
||||
if (!options.features.includes('-core')) {
|
||||
api.renderFiles('./files')
|
||||
api.extendPackage({
|
||||
scripts: {
|
||||
'dev': 'vue-cli-service serve',
|
||||
'build': 'vue-cli-service build',
|
||||
'start': 'vue-cli-service serve --prod'
|
||||
},
|
||||
dependencies: {
|
||||
'vue': '^2.5.13'
|
||||
},
|
||||
devDependencies: {
|
||||
'@vue/cli-service': '^0.1.0',
|
||||
'vue-template-compiler': '^2.5.13'
|
||||
},
|
||||
'postcss': {
|
||||
'plugins': {
|
||||
'autoprefixer': {}
|
||||
}
|
||||
},
|
||||
browserslist: [
|
||||
'> 1%',
|
||||
'last 2 versions',
|
||||
'not ie <= 8'
|
||||
]
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = api => {
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = api => {
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = api => {
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = api => {
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = api => {
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = api => {
|
||||
|
||||
}
|
||||
2
packages/@vue/cli/lib/promptModules/e2e.js
Normal file
2
packages/@vue/cli/lib/promptModules/e2e.js
Normal file
@@ -0,0 +1,2 @@
|
||||
module.exports = cli => {
|
||||
}
|
||||
2
packages/@vue/cli/lib/promptModules/eslint.js
Normal file
2
packages/@vue/cli/lib/promptModules/eslint.js
Normal file
@@ -0,0 +1,2 @@
|
||||
module.exports = cli => {
|
||||
}
|
||||
2
packages/@vue/cli/lib/promptModules/pwa.js
Normal file
2
packages/@vue/cli/lib/promptModules/pwa.js
Normal file
@@ -0,0 +1,2 @@
|
||||
module.exports = cli => {
|
||||
}
|
||||
2
packages/@vue/cli/lib/promptModules/router.js
Normal file
2
packages/@vue/cli/lib/promptModules/router.js
Normal file
@@ -0,0 +1,2 @@
|
||||
module.exports = cli => {
|
||||
}
|
||||
2
packages/@vue/cli/lib/promptModules/typescript.js
Normal file
2
packages/@vue/cli/lib/promptModules/typescript.js
Normal file
@@ -0,0 +1,2 @@
|
||||
module.exports = cli => {
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
module.exports = api => {
|
||||
api.injectFeature({
|
||||
module.exports = cli => {
|
||||
cli.injectFeature({
|
||||
name: 'Unit Testing',
|
||||
value: 'unit',
|
||||
short: 'Unit'
|
||||
})
|
||||
|
||||
api.injectPrompt({
|
||||
cli.injectPrompt({
|
||||
name: 'unit',
|
||||
when: options => options.features.includes('unit'),
|
||||
when: answers => answers.features.includes('unit'),
|
||||
type: 'list',
|
||||
message: 'Pick a unit testing solution:',
|
||||
choices: [
|
||||
@@ -24,10 +24,10 @@ module.exports = api => {
|
||||
]
|
||||
})
|
||||
|
||||
api.injectPrompt({
|
||||
cli.injectPrompt({
|
||||
name: 'assertionLibrary',
|
||||
message: 'Pick an assertion library for unit tests:',
|
||||
when: options => options.unit === 'mocha',
|
||||
when: answers => answers.unit === 'mocha',
|
||||
type: 'list',
|
||||
choices: [
|
||||
{
|
||||
@@ -48,11 +48,13 @@ module.exports = api => {
|
||||
]
|
||||
})
|
||||
|
||||
api.onPromptComplete(options => {
|
||||
if (options.unit === 'mocha') {
|
||||
require('./mocha-webpack')(api, options)
|
||||
} else if (options.unit === 'jest') {
|
||||
require('./jest')(api, options)
|
||||
cli.onPromptComplete((answers, options) => {
|
||||
if (answers.unit === 'mocha') {
|
||||
options.plugins['@vue/cli-plugin-unit-mocha-webpack'] = {
|
||||
assertionLibrary: answers.assertionLibrary
|
||||
}
|
||||
} else if (answers.unit === 'jest') {
|
||||
options.plugins['@vue/cli-plugin-unit-jest'] = {}
|
||||
}
|
||||
})
|
||||
}
|
||||
2
packages/@vue/cli/lib/promptModules/vuex.js
Normal file
2
packages/@vue/cli/lib/promptModules/vuex.js
Normal file
@@ -0,0 +1,2 @@
|
||||
module.exports = cli => {
|
||||
}
|
||||
@@ -1,3 +1,36 @@
|
||||
module.exports = async function installDeps (command, targetDir) {
|
||||
// TODO think about dep strategy
|
||||
const { spawn } = require('child_process')
|
||||
|
||||
module.exports = function installDeps (command, targetDir, deps) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const args = []
|
||||
if (command === 'npm') {
|
||||
args.push('install', '--loglevel', 'error')
|
||||
if (deps) {
|
||||
args.push('--save-dev')
|
||||
}
|
||||
} else if (command === 'yarn') {
|
||||
if (deps) {
|
||||
args.push('add', '--dev')
|
||||
}
|
||||
args.push('--silent')
|
||||
} else {
|
||||
throw new Error(`unknown package manager: ${command}`)
|
||||
}
|
||||
if (deps) {
|
||||
args.push.apply(args, deps)
|
||||
}
|
||||
|
||||
const child = spawn(command, args, {
|
||||
cwd: targetDir,
|
||||
stdio: 'inherit'
|
||||
})
|
||||
child.on('close', code => {
|
||||
if (code !== 0) {
|
||||
return reject(
|
||||
`command failed: ${command} ${args.join(' ')}`
|
||||
)
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = function resolveInstalledGenerators () {
|
||||
// TODO
|
||||
return []
|
||||
}
|
||||
@@ -3,9 +3,6 @@ const path = require('path')
|
||||
const mkdirp = require('mkdirp')
|
||||
|
||||
module.exports = function writeFileTree (dir, files) {
|
||||
if (process.env.DEBUG) {
|
||||
return
|
||||
}
|
||||
for (const name in files) {
|
||||
const filePath = path.join(dir, name)
|
||||
mkdirp.sync(path.dirname(filePath))
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"isbinaryfile": "^3.0.2",
|
||||
"klaw-sync": "^3.0.2",
|
||||
"mkdirp": "^0.5.1",
|
||||
"resolve": "^1.5.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"semver": "^5.4.1"
|
||||
},
|
||||
|
||||
@@ -6061,7 +6061,7 @@ resolve@1.1.7:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
|
||||
|
||||
resolve@^1.4.0:
|
||||
resolve@^1.4.0, resolve@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user