webpack構建vue項目(再談配置)

webpack配置起來確實麻煩,這不,以前用剛配好了vue1+的版本,結果在(部分)安卓機上測試,發現存在開啓熱加載(dev-server)的狀況下不能識別vue語法的問題,試了不少方法,都沒能很好的解決,最後索性將vue升級到2+,居然就能識別了,好吧!css

1.先分享一下webpack配置vue2+的一些不一樣(本人親測):html

(1)dependencies中的vue默認安裝2+,直接運行,會報以下錯:[Vue warn]: Failed to mount component: template or render function not defined。
若是dependencies中的vue選擇^1.0.26,那麼devDependencies中對應的vue-loader最好選擇^7.3.0,vue-hot-reload-api最好選擇^1.2.0,不然就會報錯。
(2)若是vue選擇安裝1+,dependencies中的vue-router最好選擇^0.7.13(默認安裝2+,沒法識別router.map()這個方法)。
(3)若是vue選擇安裝1+,dependencies中的vue-validator最好選擇^2.0.0(默認安裝2.1.7)。
(4)若是vue選擇安裝1+,後面在開啓webpack dev server的時候,處於同一內網中的安卓手機訪問本地設備的輸出頁面會出現不識別vue語法的兼容問題,ios手機能夠正常訪問和解析,可是開啓別的server再來訪問並不會出現這種兼容問題,因此爲了測試方便,建議vue選擇安裝2.0的版本。
(5)若是vue選擇安裝2+,vue2.0有兩種構建模式,默認狀況下運行構建,可是不能解析單文件的template模板,因此要使用獨立構建,須要在alias中指定vue$的模塊別名地址,即vue

// 其餘解決方案
resolve: {
    // require時省略的擴展名,遇到.vue結尾的也要去加載
    extensions: ['','.js', '.vue'],
    // 模塊別名地址,方便後續直接引用別名,無須寫長長的地址,注意若是後續不能識別該別名,須要先設置root
    root:"../node_modules",
    alias:{
        'vue$':'vue/dist/vue.js'
    }
}, 

(6)若是vue選擇安裝2+,對應的vue-validator就必須安裝3+,不然會報錯,可是這樣一來在開啓webpack dev server的時候,又會出現安卓手機不識別vue-validator的兼容問題,ios手機能夠正常訪問和解析,因此爲了測試方便,改用其餘的基於vue的表單驗證插件,即vuerify,須要引入vue2+、vuerify和v-vuerify-next。
(7)若是vue選擇安裝2+,涉及到的loader儘可能升級到最新,不然會報錯;最好是將vue升級到2.0.7,對應的vue-loader升級到8.5.4,vue-html-loader升級到1.2.3,vue-hot-reload-api升級到2.0.6。
(8)若是vue選擇安裝2+,對應的router要升級到2+,可是這時以前使用的表單驗證插件就會作出問題(例如:vue-validator-3.0.0-alpha.1和vuerify+v-vuerify-next這兩款插件在路由跳轉的時候都會報錯,嘗試了不少方法都無濟於事,感受仍是版本匹配的問題),awesome-vue集合了來自社區貢獻的數以千計的插件和庫,在這裏我找了一些專門針對vue2+的表單驗證插件,發現Vee-Validate和Vue-Easy-Validator這兩款插件沒有出現以前遇到的問題,並且前者的英文文檔寫得至關詳細,贊之。node

2.不要小瞧版本匹配問題,webpack自帶插件和第三方插件,vue和裏面須要引入的插件,再加上各類模塊加載器,有時匹配對了一個,另外一個又會出問題,我就是在這裏浪費了太多的時間,最後索性跟着版本走,強勢擁抱2+。關於vue2+的語法,官網裏寫得很詳細,這裏就不贅述,我仍是接着講webpack配置問題吧:jquery

(1)配置文件裏的入口和出口:webpack

// 入口文件,路徑相對於本文件所在的位置,能夠寫成字符串、數組、對象
entry: {
    // 如下是單頁面的入口路徑
    index: path.resolve(__dirname, "../entry/index.js"),

    // 須要被提取爲公共模塊的羣組
    vendors: ["vue","vue-router","vue-resource","vee-validate","jquery"],
},

// 輸出配置
output: {
    // 輸出的js文件,路徑相對於本文件所在的位置
    path: path.resolve(__dirname, "../output/js/"),

    // 將入口文件中涉及到的同步加載的js文件打包成一個js文件,基於文件的md5生成hash名稱的script來防止緩存
    filename: "[name].[hash].js",

    // 異步加載的業務模塊,例如按需加載的.vue單文件組件
    chunkFilename: "[id].[name].[chunkHash].js"
}

這裏須要注意的點很多,我主要說兩個:ios

一個是publicPath,上次說過測試環境裏寫成 config.output.publicPath = "/",不建議在生產環境裏動它,但最近導出文件的時候若是不設置publicPath,按需加載的.vue單文件組件中的script路徑會報錯,因此仍是得設置一下publicPath,其路徑能夠寫成相對於生成的html單文件所在位置的相對路徑;web

另外一個就是chunkFilename,上次沒怎麼提它,主要是沒怎麼用到它,若是項目裏涉及到異步加載的業務模塊,就不得不提它了。若是使用AMD風格的requireJS來實現路由組件的懶加載,例如:vue-router

const Register = resolve => require(["../src/private/components/register"],resolve);

這樣寫的話,這個組件就不會和entry中引入的js文件一塊兒打包,而是單獨打包成一個js文件,名字就是這裏的chunkFilename,帶一個自動分配的,可讀性不好的[id]。若是想在命名的時候更有歸屬感,即帶上一個[name],可使用require.ensure來實現路由組件的懶加載,例如:api

const Register = resolve => require.ensure(["../src/private/components/register"], () => resolve(require("../src/private/components/register")), "register");

若是要把某個路由下的全部組件都打包在同個異步chunk中,無須明確列出require.ensure的依賴,即傳空數組就行。若是你還想在按需加載某個模塊的同時執行一些代碼,能夠寫成:

const Register = resolve => {
    require.ensure(["../src/private/components/register"], () => {
        // 這裏能夠寫異步加載指定模塊以前的代碼
        resolve(require("../src/private/components/register"));
        // 這裏能夠寫異步加載指定模塊以後的代碼
    },"register")
}

(2)在測試環境中寫了 config.output.publicPath = "/" 以後,當前配置文件下的不少相對路徑都是相對於這個來設定,即不少涉及到相對路徑的地方須要發生相應的變化,不然開啓dev-server以後會報錯找不到文件的錯誤,那麼有哪些地方須要改呢,我我的建議改如下幾個地方:

某些模塊加載器的路徑,例如加載圖片的url-loader和加載圖標的file-loader;

某些插件的路徑,例如生成單個html文件的HtmlWebpackPlugin,提取css單文件的ExtractTextPlugin

(3)爲了防止「找不到favicon.ico文件」這種錯誤帶來的干擾,找一張圖塞到項目根目錄下,輸出的時候直接在 new HtmlWebpackPlugin 插件參數列中寫 favicon: "favicon.ico",而後開啓dev-server就不會報錯啦,可是生產環境下仍是會報錯,緣由是導出的位置和輸出的js文件同級,因此得把它從新塞到和輸出的html文件同級,這裏我是用的CopyWebpackPlugin這款插件(第三方插件),代碼以下:

// 把指定的文件複製到指定的目錄
new CopyWebpackPlugin([
    // from寫的是源文件名,這裏的位置是在項目根目錄下,to是寫將要複製過去的目錄位置,相對於輸出的js文件
    {from:'favicon.ico',to:"../html/favicon.ico"}
])

(4)對於.vue單文件,css默認是內部樣式,如今要把它裏面的css提取出來變成外部導入,可是若是.vue單文件組件是按需加載,那麼此設置無效,即會從新變回內部樣式(也多是我本身弄錯了),代碼以下:

vue: {
    loaders: {
        css: ExtractTextPlugin.extract('vue-style-loader', 'css-loader'),
    }
}

(5)config.devtool這個就看本身喜愛吧,開發環境下推薦使用cheap-module-eval-source-map,生產環境下推薦使用cheap-source-map或source-map,後者獲得的.map文件體積比較大,可是可以徹底還原之前的js代碼

(6)若是要提取入口文件裏面的公共模塊,配置文件中必需要有如下三步:

entry: {
        // path.resolve([from ...], to) 將to參數解析爲絕對路徑
        index:path.resolve(__dirname, '.index.js'),
        // 須要被提取爲公共模塊的羣組
        vendors:['vue','vue-router','jquery']
},
new webpack.optimize.CommonsChunkPlugin({
        name: 'vendors',
        filename: 'vendors.js',
}), 

第三步是 new HtmlWebpackPlugin 插件參數列裏的chunks裏必定要引入vendors;

(7)若是將css單獨提取出來,配置文件中必需要有如下三步:

var ExtractTextPlugin = require('extract-text-webpack-plugin');
// module.loaders裏添加
{
      test: /\.css$/,                  
      // loader: 'style-loader!css-loader',
      // 將樣式抽取出來爲獨立的文件
      loader: ExtractTextPlugin.extract("style-loader", "css-loader"),
      exclude: /node_modules/
}
new ExtractTextPlugin("../css/[name].[contenthash].css")

3.其餘須要注意的地方:

(1)html文件中最好只寫和html相關的標籤語言,儘可能不要導入外部的css或者js文件,也儘可能不要寫內部樣式或者在<script>標籤裏寫js代碼
(2)css文件中寫url的時候注意路徑問題,特別是在配置文件裏設置了publicPath的狀況下
(3)js文件中涉及到文件引入的,能夠用require或define或import from,注意採用這種引入的前提是被引入文件已經進行了模塊化的代碼規範
(4)若是不想單獨引入某個文件,能夠在全局掛載插件中進行設置,區別於window掛載
(5)vue組件中涉及到圖片路徑(主要是src形式)報錯的,能夠在路徑外層加上require(),這樣測試環境下是沒有問題的,可是生產環境下可能還會報錯,關鍵在於弄清楚兩種環境下圖片的相對路徑分別是相對於誰
(6)webpack加載css的時候,遇到font-family必定要去掉屬性值的空格和雙引號,否則解析出來的樣式會出錯

 

未完待續~

相關文章
相關標籤/搜索