基於 Webpack 3 的 Vue.js 工程項目腳手架從屬於筆者的 Web 前端入門與工程實踐,是筆者基於兄弟項目 React 腳手架改造而來,兩者在 Webpack 配置層面差別不大。更多關於 Vue.js 或者前端開發相關的資料連接能夠參考Vue.js 學習與實踐資料索引, Vue.js 與前端工程化實踐系列文章以及 Webpack 學習與資料索引,對於其中淺薄的工程化的思考能夠參考 2016-個人前端之路:工具化與工程化。javascript
create-webpack-app 是筆者對於平常工做中的基於 React/Vue.js 技術棧與實踐的沉澱,dev-config/* 與 package.json 構成了基礎的腳手架,支持最新的開發流程與默認的生產環境優化;模板項目包含特性以下:css
技術棧支持:使用 ES6/ES7 語法、容許使用 CSS Modules、SCSS、Less 而且使用 PostCSS 進行自動 Polyfill、支持使用 styled-component 進行 CSS-in-JS 樣式控制、使用 Flow 做爲靜態類型檢測工具、使用 Jest 做爲默認的測試框架html
開發環境:使用 WebpackDevServer 部署開發服務器、使用 React Hot Loader 進行組件熱加載、使用 Babel 進行代碼轉換、使用 ESLint 進行代碼檢測、使用 DllPlugin 做爲開發環境下公共代碼提取工具以優化編譯速度前端
生產環境:使用 CommonChunksPlugin 做爲生產環境下公共代碼提取工具、使用 Prepack & prepack-webpack-plugin 進行代碼優化、使用 offline-plugin 添加簡單的 PWA 特性加強vue
部署方式:支持獨立部署(Hash 方式切換路由)、支持服務端部署、支持服務端渲染java
本部分便是針對 Vue.js 項目的腳手架,咱們能夠直接拷貝該項目來展現部分開發模式或者做爲模板項目使用:node
# 下載本項目 git clone https://github.com/wxyyxc1992/create-webpack-app # 可使用 yarn install & npm start 直接運行本項目 # 僅保留 dev-config、package.json、src/client.js、src/ssr_server.js mkdir /path/to/your/project # 拷貝必須的啓動文件 cp -r vue/dev-config/ /path/to/your/project cp vue/package.json /path/to/your/project cp vue/src/client.js /path/to/your/project/src/ # 安裝運行依賴 cd /path/to/your/project yarn install / npm install # 有時候須要安裝 better-npm-run npm install better-npm-run -g # 啓動項目 npm start # 編譯爲純客戶端部署模式,即單個 HTML 頁面 npm run build # 進行依賴升級檢查 npm run update
開發環境下的操做面板:react
編譯以後的包體分析:webpack
本模板相較於官方的 webpack-simple 功能稍微複雜,而且引入了完整的 Flow、Jest 等技術棧配置,同時優化了 Webpack 的構建性能。git
!Important! 項目還沒有支持 SSR
create-webpack-app 默認的應用配置位於 dev-config/apps.config.js 文件中,該文件也是 dev-config/ 文件夾下惟一與應用業務相關的文件;該文件定義了不一樣應用中的須要配置的應用相關信息。create-webpack-app 定位爲單項目多應用的模板,所以咱們能夠在apps
鍵下配置項目設計的應用入口;在打包時會自動將多個應用並行編譯而且提取出全部公共的代碼。每一個應用須要提供惟一編號、入口文件地址、模板頁面、是否編譯等信息;接下來 devServer 則是定義了當前正在開發的應用入口,ssrServer 定義了打包時須要使用的渲染服務器入口,其會在執行 npm run build:ssr
時調用,proxy
與 api
則定義了後端服務器信息,開發者能夠根據業務需求自行使用。典型的 apps.config.js 文件配置以下:
module.exports = { //基本的應用配置信息 apps: [ //HelloWorld { id: "pwa", src: "./pwa/client.js", indexPage: defaultIndexPage, compiled: true } ], //開發入口配置 devServer: { appEntrySrc: "./pwa/client.js", //當前待調試的APP的入口文件 port: 3000 //監聽的Server端口 }, //用於服務端渲染的Server路徑 ssrServer: { serverEntrySrc: "./pwa/ssr_server.js" }, //依賴項配置 proxy: { //後端服務器地址 http://your.backend/ "/api/*": "http://localhost:3001" }, //後端 api 配置,這樣配置能夠避免將測試服務器端口暴露出去 api: { dev: {}, prod: {} } };
應用入口文件則遵循官方的單文件組件範式:
import Vue from 'vue'; import App from './application/App.vue'; new Vue({ el: '#root', render: h => h(App) });
在 dev-config/webpack/loaders.js 文件中定義了模板所須要的加載器,默認支持 js、jsx、vue、ts、tsx、css、scss、less、json 以及各類資源文件等常見格式。當咱們執行 npm start
命令時,會自動啓動dev-config/server/devServer.js 文件中定義的 Webpack 開發服務器,該服務器會使用 dev-config/webpack.config.js 文件進行配置項生成。值得一提的是,WebpackDevServer 中的 contentBase 設置爲了 path.join(__dirname, "../../public")
,也就是將 /public 目錄做爲開發服務器的默認根目錄。熱加載配置包括如下步驟:
開發時應用入口設置:
entry = [ `webpack-dev-server/client?http://0.0.0.0:${appsConfig.devServer.port}`, "webpack/hot/only-dev-server", require("./apps.config.js").devServer.appEntrySrc ];
Babel 配置,默認的 Babel 文件位於 dev-config/tool/.babelrc:
... "plugins": [ ...
create-webpack-app 支持 SCSS、CSS Modules 以及 styled-components 這三種樣式定義方式。
create-webpack-app 使用了 CommonsChunkPlugin 進行代碼分割,默認在 dev-config/webpack/plugins.js 文件中定義了對於 node_modules 中依賴文件的自動抽取:
new webpack.optimize.CommonsChunkPlugin({ name: "vendor", filename: "vendor.bundle.js", minChunks: ({ resource }) => resource && resource.indexOf("node_modules") >= 0 && resource.match(/\.(js|less|scss)$/) })
該插件會自動生成 vendor.bundle.js 文件,咱們須要在應用入口文件以前引用它;開發者也能夠自定義 CommonsChunkPlugin 插件以自定義須要提取的公共代碼。
隨着項目複雜度與體量的增長,咱們發現初始化編譯與增量編譯的速度都有所降低,爲了提高構建性能首先咱們要作的就是保持 Webpack 版本的更新速度;此外,create-webpack-app 還默認啓動了 DllPlugin 在開發狀態下將全部的依賴提取爲 dll 文件以提升增量編譯的速度。由於考慮到靈活性,即隨時有可能增減依賴的狀況,create-webpack-app 目前設置的是每次使用 npm start
的時候都會從新生成 dll 文件;若是是已經穩定的項目能夠考慮僅生成一次依賴。
const path = require("path"); const pkg = require("../package.json"); const webpack = require("webpack"); let dllConfig = { name: "vendor", entry: Object.keys(pkg.dependencies), output: { path: path.resolve(__dirname, "../public/dll"), filename: "vendor.bundle.js", library: "vendor_[hash]" }, plugins: [ new webpack.DllPlugin({ name: "vendor_[hash]", path: path.resolve(__dirname, "../public/dll/manifest.json") }) ] }; module.exports = dllConfig; // 在 public/index.html 文件中須要引入該依賴 // index.html <script src="dll/vendor.bundle.js"></script>
create-webpack-app 中也內置了其餘的編譯以後的代碼性能優化插件,首先是利用 Webpack 3 的 Scope Hositing 特性來優化生成的模塊;這一點須要使用 ModuleConcatenationPlugin 插件。此外,還使用了 PrepackWebpackPlugin 對於打包生成的文件進行過濾與重構;不過須要注意的是 PrepackWebpackPlugin 會較大地下降編譯速度,所以也是能夠根據實際的項目狀況選用。
// 使用 Scope Hositing 特性 new webpack.optimize.ModuleConcatenationPlugin(), // 使用 Prepack 優化包體大小 // 暫時存在 Bug,等待修復 // 使用前 21 - 425 // 使用後 21 - 433 new PrepackWebpackPlugin({ mathRandomSeed: "0" }),
create-webpack-app 中只是簡單地使用了 Offline Plugin,其配置以下:
// webpack.config.js example var OfflinePlugin = require('offline-plugin'); module.exports = { // ... plugins: [ // ... other plugins // it's always better if OfflinePlugin is the last plugin added new OfflinePlugin() ] // ... } // render.js require('offline-plugin/runtime').install();
觀察網絡面板中的資源請求狀況,咱們能夠看到腳本等已經被緩存在了本地:
本小節僅表明本人我的意見,請多多指點
官方文檔中介紹的單文件組件(Single File Component)包含了 template、script、style 這三個部分,筆者感受算是典型的前端項目三要素。不過筆者習慣的開發模式是以 JavaScript 爲中心,即 JavaScript 文件單獨可測試,而不是和樣式以及標籤混合在一塊兒(JSX 本質上也是 JavaScript)。所以在該模板中,筆者是將標籤、樣式與腳本分到了三個文件中:
// App.js // @flow export default { name: "app", data() { return { msg: "Vue.js & Webpack App Boilerplate by 王下邀月熊" }; } }; // App.scss #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } // App.vue <template> <div id="app"> <img src="../../public/assets/logo.png"> <h1>{{ msg }}</h1> <h2>Essential Links</h2> <ul> <li><a href="https://vuejs.org" target="_blank">Core Docs</a></li> <li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li> <li><a href="https://gitter.im/vuejs/vue" target="_blank">Gitter Chat</a></li> <li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li> </ul> <h2>Ecosystem</h2> <ul> <li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li> <li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li> <li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li> <li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li> </ul> </div> </template> <script> import App from './App.js'; export default App; </script> <style lang="scss"> @import "App"; </style>
筆者我的感受這種模式更符合單一職責原則,對於複雜的組件可以提升代碼可讀性;同時將 JavaScript 代碼獨立出來也能更加方便地進行單元測試與類型檢測等操做。
詳細的 JavaScript 編程樣式指南已經遷移到了 Web 項目開發風格指南與 JavaScript 編程樣式指南,涵蓋了基本原則闡述、代碼風格、代碼格式化與語法檢測、項目架構等幾個部分。不過本部分建議是相似於 Create React APP 配置提交時自動進行格式化,首先須要安裝以下依賴:
npm install --save husky lint-staged prettier // or yarn add husky lint-staged prettier
而後在 package.json 中添加 Hook:
"scripts": { "precommit": "lint-staged", ...
同時添加 lint-staged 配置:
"dependencies": { // ... }, + "lint-staged": { + "{src,stories}/**/*.{js,jsx,json,css}": [ + "prettier --single-quote --write", + "git add" + ] + }, "scripts": {
這樣當咱們提交代碼時就會自動使用 Prettier 優化代碼,不過須要注意的是這種配置僅做用於根目錄下;若是某個倉庫中包含了多個應用配置,那麼咱們還須要在根目錄下單獨配置腳本。咱們也可使用 ./node_modules/.bin/prettier --single-quote --write "src/**/*.{js,jsx}"
來手動進行項目文件的格式化。另外由於模板項目時放置在了子文件下,若是使用者但願使用該特性須要手動地在 package.json 中添加 "precommit": "lint-staged"
這個配置。