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…