學習筆記-webpack 入門

webpack 本質上是一個打包工具,它會根據代碼的內容解析模塊依賴,幫助咱們把多個模塊的代碼打包。javascript

開始接觸wbpack是在vue-cli腳手架中,用於打包、壓縮以及一些各個環境的配置,當初花了些時間來研究它,發現裏面的可配置項仍是不少的。最近面試中也有問到過關於webpack的配置,今天從新把筆記中的記錄結合官網最新的API作了一個整理,以備後續查閱!css

webpack官網地址html

webpack中包含如下幾個主要部分:

entry入口:

用來指定一個入口起點(或多個入口起點),進入入口起點後,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的。前端

module.exports = {
  entry: './src/index.js'
  }
複製代碼

output輸出:

output屬性告訴webpack在哪裏輸出它所建立的bundles,以及如何命名這些文件,默認值爲./dist。基本上,整個應用程序結構,都會被編譯到你指定的輸出路徑的文件夾中。你能夠經過在配置中指定一個output字段,來配置這些處理過程。vue

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
 }

複製代碼

loader解析器:

webpack 可以去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript),將全部類型的文件轉換爲webpack可以處理的有效模塊,而後你就能夠利用 webpack 的打包能力,對它們進行處理。java

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module:{
      rules:[
          {
              test:/\.css$/,
              use:[
                  'style-loader',
                  'css-loader'
              ]
          },
          {
              test:/\.(png|svg|jpg|gif)$/,
              use:[
                  'file-loader'
              ]
          },
          {
              test:/\.(woff|woff2|eot|ttf|otf)/,
              use:[
                  'file-loader'
              ]
          },
          {
              test:/\.(csv|tsv)$/,
              use:[
                  'csv-loader'
              ]
          },
          {
              test:/\.xml$/,
              use:[
                  'xml-loader'
              ]
          }
      ]
  }
};

複製代碼

plugins插件:

plugins並非直接操做單個文件,它直接對整個構建過程起做用下面列舉了一些咱們經常使用的plugins和他的用插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量。插件接口功能極其強大,能夠用來處理各類各樣的任務,例如開啓gzip壓縮,開發環境去掉警告,debugger,console註釋等。node

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');


module.exports = {
    entry: {
        app: './src/index.js'
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    },
    // 插件管理,需先進行引入,再使用
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'Output Management'
        })
    ],
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },

};

複製代碼

1、非項目環境下的 webpack 的配置以及使用:

此處省略了官網的一步步下載loader包並配置的過程,如需看詳細的版本能夠移步到官網詳細查閱。 當前版本webpack@4.40.2 webpack-cli@3.3.9webpack

關於webpack的下載和初始化:ios

<!--初始化package.json-->

npm init -y

<!--下載webpack-->

npm install webpack webpack-cli --save-dev
複製代碼

初始化後的目錄以下:git

每一個文件裏的具體代碼以下:

package.json:

{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    // 此處配置的build ,可在後期用 npm run build 直接運行壓縮打包
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^3.2.0",
    "csv-loader": "^3.0.2",
    "file-loader": "^4.2.0",
    "style-loader": "^1.0.0",
    "webpack": "^4.40.2",
    "webpack-cli": "^3.3.9",
    "xml-loader": "^1.2.1"
  },
  "dependencies": {
    "lodash": "^4.17.15"
  }
}

複製代碼

index.html前臺頁面:

<!doctype html>
<html>
  <head>
    <title>起步</title>
  </head>
  <body>
  <!--這個bundle.js就是咱們打包後的js壓縮文件,配置在webpack.config.js中-->
    <script src="bundle.js"></script>
  </body>
</html>
複製代碼

index.js:

import _ from 'lodash';
import './style.css';
import Img from './img.jpg';
import Data from './data.xml'


function component() {
    var element = document.createElement('div');
  
    element.innerHTML = _.join(['Hello', 'webpack!'], ' ');
   
    return element;
  }
  
  document.body.appendChild(component());

複製代碼

webpack.config.js配置頁面:

const path = require('path');

module.exports = {
<!--這裏是入口-->
  entry: './src/index.js',
  
  <!--這裏是壓縮後的導出-->
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  
  <!--這裏是咱們下載的loader,不一樣格式的文件處理-->
  module:{
      rules:[
          {
              test:/\.css$/,
              use:[
                  'style-loader',
                  'css-loader'
              ]
          },
          {
              test:/\.(png|svg|jpg|gif)$/,
              use:[
                  'file-loader'
              ]
          },
          {
              test:/\.(woff|woff2|eot|ttf|otf)/,
              use:[
                  'file-loader'
              ]
          },
          {
              test:/\.(csv|tsv)$/,
              use:[
                  'csv-loader'
              ]
          },
          {
              test:/\.xml$/,
              use:[
                  'xml-loader'
              ]
          }
      ]
  }
};

複製代碼

接下來你須要下載package 裏面的依賴:

cnpm install
複製代碼

執行壓縮:

npm run build
複製代碼

而後打開index.html 能夠看到以下頁面:


好了到這裏咱們能夠正常顯示頁面了,那接下來能夠再添加一些其餘文件,css,img,data來壓縮試試:

style.css:

.hello{
    color:red;
    font-family: 'MyFont';
    background:url('./img.jpg');

}
複製代碼

index.js

import _ from 'lodash';
import './style.css';
import Img from './img.jpg';
import Data from './data.xml'

function component() {
    var element = document.createElement('div');
  
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    // 添加css
    element.classList.add('hello');
    
    // 將圖像添加到咱們現有到div
    var myImg =new Image();
        myImg.src = Img;

    element.appendChild(myImg)
    
    // 添加數據
    console.log(Data)
    
    return element;
  }
  
  document.body.appendChild(component());

複製代碼

而後再執行壓縮,查看結果:


壓縮後的文件:


頁面展現:


到目前爲止,咱們實現了將打包都壓縮到一個文件中,可是若是是大型項目中的話,這樣是不可取的,接下來咱們配置分別將不一樣文件壓縮並輸出不一樣的文件。

plugins插件之: HtmlWebpackPlugin( 配置多個文件分別打包 )

新建一個print.js文件在src

npm install --save-dev html-webpack-plugin
複製代碼

webpack.config.js配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 引入

module.exports = {
  // 配置多入口
  entry: {
    app:'./src/index.js',
    print:'./src/print.js'
  },
  //分別打包成不一樣名稱的js文件
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  // 配置plugins模塊
  plugins:[
      new HtmlWebpackPlugin({
          title:'Output Management'
      })
  ]

};
複製代碼

執行打包,而後打開index.html,你就會看到 HtmlWebpackPlugin 建立了一個全新的文件,全部的 bundle 會自動添加到 html 中。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Output Management</title>
  </head>
  <body>
  <!--我當前只打包了這兩個文件,plugins就幫我都引入到了index.html-->
  <script type="text/javascript" src="app.bundle.js"></script>
  <script type="text/javascript" src="print.bundle.js"></script>
  </body>
</html>

複製代碼

打包到dist 文件下

plugins插件之:clean-webpack-plugin( 每次打包清理dist文件夾 )

一般,在每次構建前清理/dist文件夾,也是比較推薦的作法。

npm install clean-webpack-plugin --save-dev
複製代碼

webpack.config.js配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

/*
*此處有坑,在webpack的中文文檔中這裏的引入方式仍是原來的方式
*const CleanWebpackPlugin = require('clean-webpack-plugin');
*如下是正確的引入方式,小夥伴們請注意哦!
*/

const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    entry: {
        app: './src/index.js',
        print: './src/print.js'
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'Output Management'
        })
    ]

};

複製代碼

執行後看到,咱們到dist文件中除了index.html 和咱們打包到兩個文件,就沒有了其餘冗餘的文件了。

plugins插件之:source-map ( 文件映射 )

webpack 打包源代碼時,可能會很難追蹤到錯誤和警告在源代碼中的原始位置。例如,若是將三個源文件(a.js, b.js 和 c.js)打包到一個 bundle(bundle.js)中,而其中一個源文件包含一個錯誤,那麼堆棧跟蹤就會簡單地指向到 bundle.js。這並一般沒有太多幫助,由於你可能須要準確地知道錯誤來自於哪一個源文件。source map 就提供了這個功能。

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    entry: {
        app: './src/index.js',
        print: './src/print.js'
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    // 配置 source-map
    devtool: 'inline-source-map',
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'Output Management'
        })
    ]

};
複製代碼

src/print.js中手動添加一條錯誤

export default function printMe() {
     cosnole.error('I get called from print.js!');
  }

複製代碼

打開index頁面定位錯誤信息:


webpack-dev-server 熱加載

如今咱們每次修改完內容,還須要用npm run build 執行纔會進行打包,這用起來很麻煩,那咱們有沒有方法,改變後直接從新打包並刷新頁面呢?有的!

npm install --save-dev webpack-dev-server
複製代碼

package.json中的script中配置腳本命令,用於開啓熱加載:

"start": "webpack-dev-server --open",
複製代碼

webpack.config.js配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const webpack = require('webpack');

module.exports = {
    entry: {
        app: './src/index.js'
    },
    devtool: 'inline-source-map',
    // 添加熱加載
    devServer: {
        contentBase: './dist',
        hot: true
    },
    // 配置css loader,用來後面測試熱加載使用
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'Output Management'
        }),
        //啓動 HMR
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin()
    ],
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },

};

複製代碼

index.js:

import _ from 'lodash';
import printMe from './print.js';
// 添加一個css樣式,並引入進來
import './style.css'

function component() {
    var element = document.createElement('div');

    var btn = document.createElement('button');

    element.innerHTML = _.join(['Hello', 'webpack'], ' ');

    btn.innerHTML = 'Click me and check the console!';
    btn.onclick = printMe;

    element.appendChild(btn);

    return element;
}

document.body.appendChild(component());

// 添加熱更新,以便當 print.js 內部發生變動時能夠告訴 webpack 接受更新的模塊

if (module.hot) {
    module.hot.accept('./print.js', function () {
        console.log('Accepting the updated printMe module!');
        printMe();
    })
}

複製代碼

執行熱加載命令:npm start開啓熱加載,而後手動更改style.css中的樣式,頁面會自 動更新,此時就已經完成了webpack的最基礎的配置。


2、Vue項目中的webpack配置

上面咱們介紹了非項目中的webpack配置,這一講咱們來試着在vue項目中配置一下webpack,看看有哪些注意事項。

首先在Vue腳手架的項目中,咱們搭建完成後便可生成如下目錄:

項目中的自帶webpack版本爲: "^3.6.0"


分別有以下三個文件:

1. webpack.base.conf.js

webpack的基礎文件,裏面用於配置一些關於webpack的基礎屬性。

2. webpack.dev.conf.js

webpack關於開發環境下的配置文件。

3. webpack.prod.conf.js

webpack關於生產環境下的配置文件。


接下來分享些我項目中的基礎配置:

配置babel-polyfill

entry: {
    // 來解析es6的特性
    app: ['babel-polyfill', './src/main.js']
}
複製代碼

配置resolve

resolve: {
    // 用於設置自動添加後綴的順序
    extensions: ['.js', '.vue', '.json'],
    // alias能夠映射文件也能夠映射路徑,用於模塊別名,方便後續直接引用別名,例如:@ 表示默認src層
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
     // 避免新增默認文件,編碼時使用詳細的文件路徑,代碼會更容易解讀,也有益於提升構建速度
    mainFiles: ['index']
  }

複製代碼

配置loaderExtractTextPlugin( 抽離css樣式 )

ExtractTextPlugin該插件的主要是爲了抽離css樣式,防止將樣式打包在js中引發頁面樣式加載錯亂的現象,會單獨打一個css的包出來。這樣帶來的好處還有,分離出來的cssjs是能夠並行下載的,這樣能夠更快地加載樣式和腳本。

{
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['vue-style-loade','css-loader','less-loader', 'postcss-loader'],
        }),
        exclude: /node_modules/,
      },
      {
        test: /\.less$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader?modules', 'less-loader', 'postcss-loader'],
        }),
      }
      

複製代碼
plugins: [
    new ExtractTextPlugin("styles.css")
    ]

複製代碼

配置loader 之減小loader 編譯範圍 excludeinclude

include 表示哪些目錄中的 .js 文件須要進行 babel-loader

exclude 表示哪些目錄中的 .js 文件不要進行 babel-loader

咱們在使用 loader 的時候,儘量把 loader 應用的文件範圍縮小,只在最少數必須的代碼模塊中去使用必要的 loader,例如 node_modules 目錄下的其餘依賴類庫文件,基本就是直接編譯好可用的代碼,無須再通過 loader 處理了:

exclude:

{
        test: /\.(js|vue|jsx)$/,
        loader: 'eslint-loader',
        exclude: /node_modules/,
        enforce: 'pre',
        options: {
          fix: true
        }
      }

複製代碼

include:

{
        test: /\.js$/,
        use: [{
          loader: 'babel-loader'
        },
        {
          loader: 'iview-loader',
          options: {
            prefix: false
          }
        }
        ],
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client'), resolve('node_modules/iview/src')]

複製代碼

下面就把我整理過的這三個文件的配置完整文件分享給你們:

webpack.base.conf.js基礎配置文件:

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

function resolve(dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    // 配置babel-polyfill 來解析es6的特性
    app: ['babel-polyfill', './src/main.js']
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  //  其餘解決方案
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
    mainFiles: ['index']
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: [{
          loader: 'vue-loader',
          options: vueLoaderConfig
        },
        {
          loader: 'iview-loader',
          options: {
            prefix: false
          }
        }]
      },
      {
        test: /\.js$/,
        use: [{
          loader: 'babel-loader'
        },
        {
          loader: 'iview-loader',
          options: {
            prefix: false
          }
        }
        ],
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client'), resolve('node_modules/iview/src')]
      },
        // ExtractTextPlugin 用於將css文件從js文件中拆出來,單獨打成一個包,
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['vue-style-loade','css-loader','less-loader', 'postcss-loader'],
        }),
        exclude: /node_modules/,
      },
      {
        test: /\.less$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader?modules', 'less-loader', 'postcss-loader'],
        }),
      },
        // 把小於limit閥值大小的圖片轉爲base64字符串          
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(js|vue|jsx)$/,
        loader: 'eslint-loader',
        exclude: /node_modules/,
        enforce: 'pre',
        options: {
          fix: true
        }
      }

    ]
  },
  plugins: [
    /**
     * 將樣式提取到單獨的css文件,而不是內嵌到打包的js文件中。
     * 這樣帶來的好處時分離出來的css和js是能夠並行下載的,
     * 這樣能夠更快地加載樣式和腳本。
     */
    new ExtractTextPlugin("styles.css"),

    // 清空輸出文件夾以前的輸出文件
    new CleanWebpackPlugin(),
  ],
  node: {
    // prevent webpack from injecting useless setImmediate polyfill because Vue
    // source contains it (although only uses it if it's native). setImmediate: false, // prevent webpack from injecting mocks to Node native modules // that does not make sense for the client dgram: 'empty', fs: 'empty', net: 'empty', tls: 'empty', child_process: 'empty' } } 複製代碼

webpack.dev.conf.js開發環境配置文件:

'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const OpenBrowserPlugin = require('open-browser-webpack-plugin')

const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)

// 將基本配置合併到開發環境
const devWebpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
  },
  // cheap-module-eval-source-map is faster for development
  devtool: config.dev.devtool,

  // these devServer options should be customized in /config/index.js
  devServer: {
    clientLogLevel: 'warning',
    historyApiFallback: {
      rewrites: [
        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
      ],
    },
    hot: true,
    contentBase: false, // since we use CopyWebpackPlugin.
    compress: true,
    host: HOST || config.dev.host,
    port: PORT || config.dev.port,
    open: config.dev.autoOpenBrowser,
    overlay: config.dev.errorOverlay
      ? { warnings: false, errors: true }
      : false,
    publicPath: config.dev.assetsPublicPath,
    proxy: config.dev.proxyTable,
    quiet: true, // necessary for FriendlyErrorsPlugin
    watchOptions: {
      poll: config.dev.poll,
    }
  },
  plugins: [
    // vue run dev後自動打開瀏覽器插件
    new OpenBrowserPlugin({url: 'http://localhost:8080' }),

    new webpack.DefinePlugin({
      'process.env': require('../config/dev.env')
    }),
    
    // 模塊熱替換,無需整個刷新頁面
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
    new webpack.NoEmitOnErrorsPlugin(),
   
    // https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true
    }),
    // copy custom static assets
    // 拷貝插件
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.dev.assetsSubDirectory,
        ignore: ['.*']
      }
    ]),
    // 去除依賴中重複的插件
    new webpack.optimize.DedupePlugin() ,

    /**
     * 爲組件分配ID,經過這個插件webpack能夠分析和優先考慮使用最多的模塊,
     * 併爲它們分配最小的ID
     */
    new webpack.optimize.OccurrenceOrderPlugin()
  ]
})

module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = process.env.PORT || config.dev.port
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err)
    } else {
      // publish the new Port, necessary for e2e tests
      process.env.PORT = port
      // add port to devServer config
      devWebpackConfig.devServer.port = port

      // Add FriendlyErrorsPlugin
      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
        compilationSuccessInfo: {
          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
        },
        onErrors: config.dev.notifyOnErrors
        ? utils.createNotifierCallback()
        : undefined
      }))

      resolve(devWebpackConfig)
    }
  })
})

複製代碼

webpack.prod.conf.js生產環境的配置文件:

'use strict'
const version = require('../package.json').version || '';
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const zip = require('zip-webpack-plugin')

const env = require('../config/prod.env')

// 將基本配置合併到生產環境
const webpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true,
      usePostCSS: true
    })
  },
  devtool: config.build.productionSourceMap ? config.build.devtool : false,
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    // 對js文件進行壓縮
    new UglifyJsPlugin({
      extractComments: {
        // 根據條件保存須要保留的註釋
        condition: function (a, data) {
          return /app.\w+.js$/.test(data.file);
        },
        //存儲提取的註釋的文件名調用
        banner: 'version:' + version,
      },

      // 部分格式化,根據須要配置
      uglifyOptions: {
        compress: {
          warnings: false,      // 自動刪除警告
          drop_console: true,   // 自動刪除console.log
          typeofs: false,  //將typeof foo==「未定義」轉換爲foo==void 0。注意:對於IE10和早期版本有問題。
        }
      },
      sourceMap: config.build.productionSourceMap,
      parallel: true
    }),
    // extract css into its own file 
    // 將css 提取到本身的文件中
    new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css'),
      // Setting the following option to `false` will not extract CSS from codesplit chunks.
      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 
      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
      allChunks: true,
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    new OptimizeCSSPlugin({
      cssProcessorOptions: config.build.productionSourceMap
        ? { safe: true, map: { inline: false } }
        : { safe: true }
    }),
    // generate dist index.html with correct asset hash for caching.
    // you can customize output by editing /index.html
    // see https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: config.build.index,
      template: 'index.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      chunksSortMode: 'dependency'
    }),
    // keep module.id stable when vendor modules does not change
    new webpack.HashedModuleIdsPlugin(),
    // enable scope hoisting
    new webpack.optimize.ModuleConcatenationPlugin(),
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks(module) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity
    }),
    // This instance extracts shared chunks from code splitted chunks and bundles them
    // in a separate chunk, similar to the vendor chunk
    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
    // CommonsChunkPlugin:提取通用模塊文件,vue vuex vue-router axios
    new webpack.optimize.CommonsChunkPlugin({
      name: 'app',
      async: 'vendor-async',
      children: true,
      minChunks: 3
    }),

    // 拷貝插件
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
        ignore: ['.*']
      }
    ]),
    // 打成zip包,通常用於上線
    new zip({
      path: './',
      filename: `frame-fe.zip`
    }),
    /**
     * 將原來的 chunk 分紅更小的 chunk
     * 直到各個 chunk 的大小達到 option 設置的 maxSize
     */
    new webpack.optimize.AggressiveSplittingPlugin({
			minSize: 30000,
			maxSize: 50000
		}),
  ]
})

if (config.build.productionGzip) {
  const CompressionWebpackPlugin = require('compression-webpack-plugin')

  // 開啓gzip壓縮 gzip能在本來壓縮的基礎上再進行壓縮50%以上!!!
  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      asset: '[path].gz[query]',
      algorithm: 'gzip',
      test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
      ),
      threshold: 10240,
      minRatio: 0.8
    })
  )
}

if (config.build.bundleAnalyzerReport) {
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig


複製代碼

編寫時間緊張,內容稍有粗糙,正在改進中,請見諒!


參考文獻:

webpack中文文檔

webpack配置文檔

webpack構建指南

webpack-預處理-loader

webpack-插件-plugins

webpack-更多第三方插件

webpack開啓gzip壓縮

前端大全-一看就懂的webpack高級配置與優化

還有些參考文獻當時忘記保存,後續會陸續添加上,感謝閱讀!


郵箱:christine_lxq@sina.com

未完待續.....

做者:Christine    
    出處:https://juejin.im/user/594c9772128fe10065110aa5/posts
    版權全部,歡迎保留原文連接進行轉載:但願看到個人最新文章的能夠添加下關注哦!:) 
複製代碼
相關文章
相關標籤/搜索