關於wepack的使用總結以及優化探討

1、前言javascript

  不知不覺,webpack版本已經到4.0了。使用它也有很長一段時間了,回頭看看,本身木有總結webpack方面的知識,如今有空起個頭,主要是總結本身經常使用的配置和一下優化的探討,之後有啥想法也直接寫到這裏來。css

2、開始html

  webpack作啥的,怎麼配置?和gulp、grunt等構件工具備什麼區別?這些就跳過了,當初也是直接看官方文檔的,摸爬滾打走過來的。能夠參考:vue

  一、https://www.webpackjs.com/java

  二、《入門 Webpack,看這篇就夠了》node

  三、《vue-cli中webpack配置》系列webpack

      4 《webpack持久化緩存實踐ios

     5 、 https://www.jianshu.com/p/b9bf995f3712git

     六、《解決疑惑,讓你明白》
es6

3、實際項目中解析

3.一、本項目支持的功能

 1 對less編譯
 2 支持es6語法支持
 3 編譯.vue組件,並自動內聯組件樣式
 4 圖片打包,包括對html內圖片處理(利用html-loader和es6字符串模板),對小圖片生成base64
 5 利用htmlWebpackPlugin動態拼接html 的公共部分和內容部分,引入相應css/js資源,並構建到指定目錄, 對ejs模板支持
 6 對js內依賴的css分離並壓縮
 7 對js引用的公共模塊抽取分離成單獨文件
 8 區分開發環境和生產環境
 9 js 壓縮
10 靜態文件(css/js/img)hash版本支持
11 清除目標文件目錄
12 eslint支持並實現自動修復部分問題
13 vue接口請求axios支持
14 熱更新,自動編譯並刷新瀏覽器

3.二、目錄結構

|__ html
        |__ dist
              |__ income.html
              |__ index.html
        |__ src
              |__ income
                |__ income.ejs
                |__ income.js
              |__ index
                |__ index.ejs
                |__ index.js
              |__ layouts
                |__ footer.ejs
                |__ header.ejs
                |__ layout.ejs
                |__ layout.js
                |__ side-menu.e
                |__ top-nav.ejs
  |__ dist
        |__ css
        |__ img
        |__ js
              |__ income.js
              |__ index.js
              |__ manifest.js
              |__ vendors.js
  |__ src
        |__ css
        |__ img
        |__ js
              |__ component
                |__ App.vue
              |__ income.js
              |__ index.js
              |__ lib
                |__ axios.min.js
                |__ layer.js
                |__ vue.js
                |__ vue.min.js
  |__ mock
  |__ node_modules
  |__ webpack-config
        |__ .eslintrc.dev.js
        |__ .eslintrc.js
        |__ postcss.config.js
        |__ resolve.config.js
  |__ package.json
  |__ .babelrc
  |__ .eslintrc.js

4、入口entry

var entries = getEntry('./src/**/*.js') // 得到入口js文件
entries.vendors = ['vue','axios']

module.exports = {
     /* 輸入文件 */
    entry: entries
} 

一般咱們的項目中有大量的js入口文件,基本一個功能頁面有一個js,這時咱們的 entry 文件爲一個對象格式

entries 爲:

{ 
  income: './src/js/income.js',
  index: './src/js/index.js',
  vendors: [ 'vue', 'axios' ] 
}

key 值爲對應模塊的別名,webpack會依次處理這些模塊。

vendors 爲公共模塊,這裏咱們把vue, axios設置爲公共模塊,供下面進行提取公共模塊操做。

之因此能夠直接寫vue, axios,是由於咱們在 alias 裏設置了別名:

var path = require('path')

module.exports = {
  // 模塊別名的配置,爲了使用方便,通常來講全部模塊都是要配置一下別名的
  alias: {
    'vue': path.resolve(__dirname, '../src/js/lib/vue.min.js'),
    'axios': path.resolve(__dirname, '../src/js/lib/axios.min.js')
  }
} 

這裏的 path.resolve 做用是把相對路徑轉爲絕對路徑,假設我項目建在d:/demo 目錄下,

_dirname: d:\demo

path.resolve(__dirname, '../src/js/lib/vue.min.js'): d:\demo\src\js\lib\vue.min.js

getEntry() 爲獲取文件路徑的自定義函數:

/***** 獲取文件列表:輸出正確的js和html路徑 *****/
var glob = require('glob')

function getEntry(globPath) {
    var entries = {}, basename

    glob.sync(globPath).forEach(function (entry) {
    //排出layouts內的公共文件
        if(entry.indexOf('layouts') == -1 && entry.indexOf('lib') == -1){
            basename = path.basename(entry, path.extname(entry))
            entries[basename] = entry
        }
    })
    return entries
} 

一般webpack的entry入口文件,是功能性頁面的js,對於js庫等文件不須要列入入口文件進行處理。因此這裏對lib文件夾進行了排除。layouts文件夾爲獲取html路徑時須要排除的文件路徑。  

5、output介紹

module.exports = {
    output: {
        /* 輸出目錄,沒有則新建 */
        path: path.resolve(__dirname, './dist'),
        /* 靜態目錄,能夠直接從這裏取文件 */
        publicPath: 'http://www.xxx.com/dist/',
        /* 文件名 */
        filename: 'js/[name].js?v=[chunkhash:8]'
    }
}

 publicPath: 若是有這項,則html中的引用的js路徑會加上publicPath,即 http://www.xxx.com/dist/js/[name].js?v=[chunkhash:8]

 filename: 這裏能夠自定義輸出後的文件名,加上版本號

  [name] :輸入模塊的別名

  [chunkhash] : 模塊的hash值,":8"表明保留8位hash值

  [hash] : 整個編譯環境的hash值

       hash和chunkhash具體區別請看這裏

 

6、module介紹

Webpack有一個不可不說的優勢,它把全部的文件都都當作模塊處理,JavaScript代碼,CSS和fonts以及圖片等等經過合適的loader均可以被處理。

webpack利用各類loader來把不一樣格式的文件封裝成模塊加載到js內,好比css-loader, vue-loader,下面,只列舉一部分。

6.一、babel-loader

es6語法目前不少瀏覽器不支持,咱們須要將其轉化爲大部分瀏覽器支持的es5語法,這就須要babel-loader

{
    test: /\.js$/,
    loader: 'babel-loader',
    exclude: ['node_modules','./src/js/lib','./src/js/component']
}

  

6.二、 css有關的loader

css-loader style-loader post-loader less-loader

{   
    test: /\.css$/, 
    use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
    test: /\.less$/,
    use: ExtractTextPlugin.extract(['css-loader','postcss-loader','less-loader'])
}

  

對於有多個loader時,webpack v2也廢棄了v1的 " !" 鏈接,改成數組形式,且不能省略 " -loader " 以避免形成名稱混亂意思模糊,執行順序爲從右到左

postcss-loader:爲集合處理css各類問題的平臺,其上面有各類插件來處理css,咱們這裏只用到了autoprefixer插件,後面插件部分會詳解

style-loader:能夠將css以style內聯方式嵌入到html頁面

css-loader:使你可以使用相似@import 和 url(...)的方法實現 require()的功能

ExtractTextPlugin:提取css, 後面插件部分會進行詳解

6.三、css module:

把JS的模塊化思想帶入CSS中來,經過CSS模塊,全部的類名,動畫名默認都只做用於當前模塊。Webpack對CSS模塊化提供了很是好的支持,只須要在CSS loader中進行簡單配置便可,而後就能夠直接把CSS的類名傳遞到組件的代碼中,這樣作有效避免了全局污染。具體的代碼以下:

module.exports = {

    ...

    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true, // 指定啓用css modules
                            localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的類名格式
                        }
                    }
                ]
            }
        ]
    }
};

6.四、文件圖片loader

{
    test: /\.(png|jpg|gif)$/,
    loader: 'url-loader?limit=5120&name=img/[name].[ext]?v=[hash:8]'
}

6.五、字體loader

{
  test: /\.(ttf|ttc|eot|svg|woff(2))$/,
    loader: 'file-loader',
	options:{
	name: function(p){
		let tem_path = p.split(/\\fonts\\/)[1];
		tem_path = tem_path.replace(/\\/g,'/');
		return 'fonts/'+tem_path + '?v=[hash:8]';
	}
     }
}

    

7、插件plugin

插件是用來拓展Webpack功能的,它們會在整個構建過程當中生效,執行相關的任務。
Loaders和Plugins經常被弄混,可是他們實際上是徹底不一樣的東西,能夠這麼來講,loaders是在打包構建過程當中用來處理源文件的(JSX,Scss,Less..),一次處理一個,插件並不直接操做單個文件,它直接對整個構建過程其做用。

使用方法通常以下:

module: {},
plugins: [
        new ExtractTextPlugin('css/[name].css?v=[contenthash:6]'),
        new webpack.LoaderOptionsPlugin({
            options: {
                eslint: require( './webpack-config/.eslintrc.js'),
                postcss: require( './webpack-config/postcss.config.js')
            },
        })
    ]  

webpack聲明插件的方式能夠像上面的寫法也能夠以下方式:

module.exports.plugins = module.exports.plugins.concat([
        //壓縮css代碼
        new OptimizeCssAssetsPlugin({
            assetNameRegExp: /\.css/g,
            cssProcessor: require('cssnano'),
            cssProcessorOptions: { discardComments: {removeAll: true } },
            canPrint: true
        }),
        //壓縮JS代碼
        new webpack.optimize.UglifyJsPlugin({
            output: {
                comments: false, // 去掉註釋內容
            }
        })
    ]) 

7.一、extract-text-webpack-plugin 插件

默認狀況下,js依賴引入css,編譯後,css被加在js中,若是咱們想把css提取出一個單獨的文件,可使用這個插件,並能夠對提取出的css進行自定義命名和加版本hash值

new ExtractTextPlugin('css/[name].[contenthash:8].css'),

7.二、optimize-css-assets-webpack-plugin 插件

壓縮css文件,對從js中提取出的css文件亦有效

注意:此插件是在css被提取出來加了hash值後進行處理,若是css文件提出來後被命名爲  css/[name].css?v=[contenthash:8] 形式,插件的使用以下

new OptimizeCssAssetsPlugin({
            assetNameRegExp: /\.css/g,  //注意不要寫成 /\.css$/g, 不然匹配不到css文件會致使壓縮不成功
            cssProcessor: require('cssnano'),
            cssProcessorOptions: { discardComments: {removeAll: true } },
            canPrint: true
        })

7.三、webpack-plugin 插件

用於根據模板組合html各個部分,並插入對應引用的js,對先後端分離貢獻頗多,功能強大會有專門的篇章來介紹

7.四、CommonsChunkPlugin 插件

 提取js的公共模塊,此插件爲webpack自帶的插件

new webpack.optimize.CommonsChunkPlugin({
    names:  ['vendors', 'manifest'], // 公共模塊的名稱
    //filename: 'js/[name]-[chunkhash:6].js', // 公共模塊的名稱
    chunks: 'vendors',  // chunks是須要提取的模塊
    minChunks: Infinity  //公共模塊最小被引用的次數
}) 

  一般咱們的js可能會引入一些公共js文件,包括一些類庫,若是都打包在一個js中,這個js會變得很是龐大,並且一旦咱們功能頁面的js有變化,會致使打包後的js版本號進行更新而後從新加載,這個代價有些大,因此咱們會考慮把一些公共的js文件提取出一個單獨的文件,這樣在第一次訪問的時候會加載,以後就能夠緩存下來,減小服務器請求的壓力並提升加載速度。  

7.5 CleanWebpackPlugin插件

保證買次編譯以後目標文件中只保留最新的文件

new CleanWebpackPlugin(['dist']) 

 

 

 

 

------------有時間再添加了------------

8、一些優化探索

相關文章
相關標籤/搜索