改造vue-cli,讓它更好用

大雄沒了哆啦A夢發表於2018-08-15

vue-cli真的很好用?

vue-cli是一個整合了webpack+vue的腳手架,通過這個腳手架,我們可以很方便地建立一個vue專案,甚至引入了vuex和vue-router。webpack的配置對使用者來說是透明,使用者無需關注webpack的詳細配置,從而提高開發效率。
那麼vue-cli真的很好用嗎?讓我們來看看vue-cli產生的Webpack配置。首先我們看下入口檔案配置:

 entry: {
    app: './src/main.js'
 }
複製程式碼

很明顯,這是一個單入口檔案,結合vue-router是可以實現單頁面專案,打包起來也很方便,只有一個html檔案和對應的靜態檔案。這個優點同時也是缺點,即如果我們的專案比較龐大,那麼打包後所有的邏輯和業務都在一個檔案裡面。有幾個缺點:

  1. 所有邏輯和業務在一個頁面,導致頁面載入慢
  2. 打包和編譯的時候很慢,降低開發效率
  3. 高度耦合,打包的時候,如果有一個地方出錯,打包部署後,會導致整個網站都無法訪問

這些缺點也是挺致命的,想想如果你打包的時候呼叫了一個undefined方法,然後疏忽了釋出到外網去,你們老闆接下來就要找你好好聊天了。

基於以上,怎麼改進vue-cli建立的專案呢?答案當然就是分模組了,對webpack配置進行修改,打包和編譯都按模組來,這樣就不會把所有的邏輯都放入一個頁面內,編譯和打包都是按模組了,降低耦合度,利於分工開發(一個人一個模組)。

改造

1.修改目錄結構:

原先的結構:

改造vue-cli,讓它更好用
改造後的:
改造vue-cli,讓它更好用

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產生的模式進行開發也是可以的,各個模組可大可小,不過建議各個模組不要太大,不然分模組的意義就不大了。

2.修改webpack配置檔案

1、修改webpack.base.config.js入口檔案:

entry: {
    app: utils.getEntry() // 之前是./src/main.js
}
複製程式碼

utils.getEntry獲取當前正在開發的模組的入口檔案,所以我們需要一個方法可以獲取到當前正在執行的模組的方法,這裡我的思路就是在我們執行npm run sart/build的時候,去執行一個js檔案,這個js檔案可以通過prompt獲取使用者輸入他想要執行的模組,然後再啟動webpack伺服器的時候將當前要執行的模組作為引數傳入。

2、新增start.js/build.js 所以在command資料夾下新增start.js檔案,內容如下:

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內容如下:


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]就是我們輸入的模組名了

3、新增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`
}
複製程式碼

4、當然我們打包的時候,打包檔案是需要放在不同的模組下的,而不是全都都打包到一個html下,所以修改webpack.prod.config.js檔案,修改HtmlWebpackPlugin外掛,指定打包的路徑

new HtmlWebpackPlugin({
  filename: utils.getOuputFileName(),
  template: utils.getModuleTemplate(),
  inject: true,
  minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
  }
複製程式碼

5、修改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…

相關文章