vue-cli是一个整合了webpack+vue的脚手架,经过这个脚手架,咱们能够很方便地建立一个vue项目,甚至引入了vuex和vue-router。webpack的配置对用户来讲是透明,用户无需关注webpack的详细配置,从而提升开发效率。
那么vue-cli真的很好用吗?让咱们来看看vue-cli产生的Webpack配置。首先咱们看下入口文件配置:css
entry: {
app: './src/main.js'
}
复制代码
很明显,这是一个单入口文件,结合vue-router是能够实现单页面项目,打包起来也很方便,只有一个html文件和对应的静态文件。这个优势同时也是缺点,即若是咱们的项目比较庞大,那么打包后全部的逻辑和业务都在一个文件里面。有几个缺点:html
这些缺点也是挺致命的,想一想若是你打包的时候调用了一个undefined方法,而后疏忽了发布到外网去,大家老板接下来就要找你好好聊天了。vue
基于以上,怎么改进vue-cli建立的项目呢?答案固然就是分模块了,对webpack配置进行修改,打包和编译都按模块来,这样就不会把全部的逻辑都放入一个页面内,编译和打包都是按模块了,下降耦合度,利于分工开发(一我的一个模块)。node
原先的结构:webpack
modules #全部模块文件夹
└─── assets #全部模块共用的静态文件
│ │ css
│ │ img
│ │ js
└─── common #全部模块公用的js代码,好比util.js
└─── components #全部模块公用vue子模块,好比header.vue
└───src #全部模块的源码文件夹
│ └─── module_name #模块名
│ │ └─── assets #该模块特有的静态文件
│ │ │ css
│ │ │ img
│ │ │ js
│ │ └─── components #该模块特用vue子模块
│ │ └─── router #该模块特用vue路由设置
│ │ └─── util #该模块特用共有类js
│ │ │ App.vue #容器
│ │ │ index.html #模块模板文件
│ │ │ main.js #模块入口文件,文件名不要修改!!!
复制代码
咱们先看最主要的修改,即添加了modules文件夹,modules下的src文件夹下就是全部模块了,多个模块有共享的assets和components,各个模块也有各自的assets和components。经过对比,咱们能够知道,其实就是将vue-cli的src下单个模块划分红为多个模块。固然,各个模块若是你想按照原来vue-cli产生的模式进行开发也是能够的,各个模块可大可小,不过建议各个模块不要太大,否则分模块的意义就不大了。git
一、修改webpack.base.config.js入口文件:github
entry: {
app: utils.getEntry() // 以前是./src/main.js
}
复制代码
utils.getEntry获取当前正在开发的模块的入口文件,因此咱们须要一个方法能够获取到当前正在运行的模块的方法,这里个人思路就是在咱们运行npm run sart/build的时候,去执行一个js文件,这个js文件能够经过prompt获取用户输入他想要运行的模块,而后再启动webpack服务器的时候将当前要运行的模块做为参数传入。web
二、添加start.js/build.js 因此在command文件夹下添加start.js文件,内容以下:vue-router
const exec = require('child_process').exec
const { prompt } = require('inquirer')
const chalk = require('chalk')
// 询问用户想运行哪一个模块,放入module变量当中
const question = [
{
type: 'input',
name: 'module',
message: 'Module name:',
validate (val) {
if (val === '') {
return 'Module name is required!'
}
return true
}
}
]
module.exports = prompt(question).then(({module}) => {
// 要运行的模块做为参数传给dev-server.js
let cmdStr = `node ./build/dev-server.js ${module}`
var child = exec(cmdStr)
child.stdout.on('data', function(data) {
console.log('stdout: ' + data)
})
child.stderr.on('data', function(err) {
console.log(err)
process.exit()
})
})
复制代码
build.js内容以下:vuex
const { prompt } = require('inquirer')
const exec = require('child_process').exec
const chalk = require('chalk')
const ora = require('ora')
const question = [
{
type: 'input',
name: 'module',
message: 'Module name:',
validate (val) {
if (val === '') {
return 'Module name is required!'
}
return true
}
}
]
module.exports = prompt(question).then(({module}) => {
const spinner = ora(`Building ${module}...`)
spinner.start()
// 要运行的模块做为参数传给build.js
var child = exec(`node ./build/build.js ${module}`)
child.stdout.on('data', (data) => {
console.log('stdout: ' + data)
})
child.stderr.on('data', function(err) {
console.log(chalk.red(`\n building ${module} error`))
console.log(chalk.red(err))
process.exit()
})
child.on('close', function(code) {
spinner.stop()
console.log(chalk.green('\n √ Build completed!'))
})
})
复制代码
node运行的时候传入参数后,就能够经过process.argv获取了,由于咱们传入的是第二个参数,因此process.argv[2]就是咱们输入的模块名了
三、添加utils.js辅助方法
// 获取项目路径根路径
exports.getProjectPath = () => {
console.log(fs.realpathSync(process.cwd()))
return fs.realpathSync(process.cwd())
}
// 获取当前开发模块的路径, 如modules/views/test/
exports.getModulePath = () => {
var moduleName = process.argv[2]
return exports.getProjectPath() + '/modules/src/' + moduleName
}
复制代码
所以获取咱们当前模块的入口文件是这样的:
//获取子模块的入口文件,如modules/views/test/main.js
exports.getEntry = () => {
return exports.getModulePath() + '/main.js'
}
复制代码
须要打包的模块的文件是这样的:
// 根据当前正在开发的模块,获取想要打包的文件
exports.getOuputFileName = () => {
var moduleName = process.argv[2]
return exports.getProjectPath() + `/../${moduleName}/index.html`
}
复制代码
四、固然咱们打包的时候,打包文件是须要放在不一样的模块下的,而不是全都都打包到一个html下,因此修改webpack.prod.config.js文件,修改HtmlWebpackPlugin插件,指定打包的路径
new HtmlWebpackPlugin({
filename: utils.getOuputFileName(),
template: utils.getModuleTemplate(),
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
}
复制代码
五、修改package.json文件
"scripts": {
"start": "node command/start.js cross-env NODE_ENV=develoment",
"build": "node command/build.js"
},
复制代码
这样基本就完成了开发运行时,按照各个模块运行/打包了。
你们有没有发现,其实咱们各个模块之间的目录结构都差很少,每次新建模块的时候都须要去复制黏贴,很机械化,那么咱们能够作到自动化。
基本思路是咱们把模块固定的结构放在github上,附上我本身的连接:github.com/VikiLee/mod…
而后使用download-git-repo去下载到本地来。固然咱们须要经过prompt询问用户想要新建的模块名,而后从github上download下来到这个模块文件夹下就ok了,在command文件夹下新建create.js,内容以下:
const download = require('download-git-repo')
const { prompt } = require('inquirer')
const ora = require('ora')
const chalk = require('chalk')
const fs = require('fs')
var question = [
{
type: 'input',
name: 'moduleName',
message: 'Please input module name:',
validate(val) {
if(val === ''){
return 'Module name is required'
}
return true
}
}
]
module.exports = prompt(question).then(({moduleName}) => {
//模块存在
if (fs.existsSync(`./modules/src/${moduleName}`)) {
console.log(chalk.red(`Module '${moduleName}' exists!`))
process.exit()
}
const spinner = ora('Downloading template...')
spinner.start()
download(`VikiLee/module_tempate#master`, `./modules/src/${moduleName}`, (err) => {
if (err) {
console.log(chalk.red(err))
process.exit()
}
spinner.stop()
console.log(chalk.green('New module has been created successfully!'))
})
})
复制代码
同时修改package.json文件,添加create命令
"scripts": {
"create": "node command/create.js",
"start": "node command/start.js cross-env NODE_ENV=develoment",
"build": "node command/build.js"
},
复制代码
这样就经过自动化的方式新建模块了。
git地址:github.com/VikiLee/web…