webpack3.0學習筆記(三)

—— 擁抱html-webpack-plugin的甜蜜

目錄一覽

webpack3.0學習筆記(一)
webpack3.0學習筆記(二)
webpack3.0學習筆記(三)

項目源碼地址


前情概要

通過筆記(二)中一整天的試錯發現了構建多頁面時使用 html-loader 生成 html 文件的諸多弊病,重新回歸 html-webpack-plugin


html-webpack-plugin 構建頁面

筆記(一)中對 html-webpack-plugin 的理解略顯片面,用法得當即可定制出一張滿足需求的頁面。

使用 html-webpack-plugin 插件對模板進行填充完成 html 頁面的生成,其中的關鍵點是支持 ejs 的模板語法。

  • html 模板內容:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>this is webpack loader test</title>
    <link rel="stylesheet" href="<%= require('./style/index.css') %>">
    <link rel="stylesheet" href="<%= require('./style/one.css') %>">
</head>
<body>
    <img src="<%= require('./image/shana.jpg')%>" alt="shana" />
    <div class="yintama"></div>
</body>
</html>
  • webpack.config.js 配置:
const path = require('path')
const url = require('url')
const webpack = require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: {
        app: path.resolve(__dirname,'src/script/index.js'),
        one: path.resolve(__dirname,'src/script/one.js'),
        vendor: [
            'lodash'
        ]
    },
    output: {
        filename: 'js/[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
    module:{
        rules: [
            {
                test: /\.js$/,
                use: 'babel-loader',
                include: path.resolve(__dirname,'src'),
                exclude: path.resolve(__dirname,'node_modules')
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name]-[hash:6].[ext]',
                            outputPath: 'css/'
                        }
                    },
                    "extract-loader",
                    {
                        loader: "css-loader",
                        options: {
                            minimize: true
                        }
                    }
                ]
            },
            {
                test: /\.(jpe?g|png|gif|svg)$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            name: '[name]-[hash:6].[ext]',
                            outputPath: 'image/',
                            limit: 1,
                            publicPath: url.format({
                                hostname:'localhost',
                                protocol:'http:',
                                port:8080,
                                pathname:'/dist/'
                            })
                        }
                    },
                    'image-webpack-loader'
                ]
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname,'src/index.html'),
            filename: 'index.html'
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            minChunks: function(module){
                return module.context && module.context.indexOf("node_modules") !== -1;
            }
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: "manifest",
            minChunks: Infinity
        })
    ]
};

html 模板頁面中通過 ejs 語法配合 webpack 靜態資源引入方法 require('xxx'),將其引入打包流程中,配合前兩篇筆記提及的幾個 loader 對資源文件進行優化分離并獲取生成后地址,插入到新構建的 html 頁面中。

注意:測試ES6的 import 'xxx' 的形式無法引入,猜測是使用node進行模塊引用,暫時不支持該語法,使用 require('xxx') 即可。

如需將CSS文件也進行合并操作,在對應的JS文件內進行引入,配合 css-loader style-loader 解析即可。

項目的優化手段

這里只用到了 uglifyjsCommonsChunkPlugin 等方式,DLL打包類庫的問題,之后接構建具體項目的時候再進行嘗試。

  • 壓縮
  1. 圖片壓縮使用 image-webpack-loader

基本配置:

{
    test: /\.(jpe?g|png|gif|svg)$/i,
    use: [{
        loader: 'url-loader',
        options: {
            name: '[name]-[hash:6].[ext]',
            outputPath: 'image/',
            limit: 1,
            publicPath: url.format({
                hostname: 'localhost',
                protocol: 'http:',
                port: 8080,
                pathname: '/dist/'
            })
        }
    },
    {
        loader: 'image-webpack-loader',
        options: {
            gifsicle: {
                interlaced: false,
                optimizationLevel: 1
            },
            mozjpeg: {
                progressive: true,
                quality: 65
            }
        }
    }]
}

測試了下gif圖片的壓縮非常有限,還是少用這種格式的圖片。

  1. CSS壓縮使用 css-loader
{
    test: /\.css$/,
    use: [{
            loader: 'file-loader',
            options: {
                name: '[name]-[hash:6].[ext]',
                outputPath: 'css/'
            }
        },
        "extract-loader", {
            loader: "css-loader",
            options: {
                minimize: true
            }
        }
    ]
}

CSS的壓縮直接使用loader進行即可。

  1. JS壓縮使用 uglifyjs-webpack-plugin
    配置如下:
plugins: [
    new UglifyJSPlugin({
        sourceMap: true
    })
]

webpack 開啟了 devtool,這里的 sourceMap 選項設為 true

使用 uglifyjs-webpack-plugin 的時候正好說說 webpacktree shaking 特性,雖然不是什么新東西,由于支持ES6的 import 導入語法才開始廣泛使用。

  1. tree shaking

two.js 代碼如下:

function name (){
    return 'Misery'
};

function age (){
    return 30
};

export {name,age}

index.js 內容如下:

import {name} from './two.js';

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

    element.innerHTML = `hello ${name()}`;
    element.appendChild(btn);

    return element;
}

document.body.appendChild(test());

打包合并后如下:

未壓縮前

打包后 two.js 模塊中 nameage 方法都被打包了,但只有 name 方法被導出了模塊, age 由于沒有被調用而被忽略了。

壓縮后

使用 uglifyjs-webpack-plugin 壓縮后 age 方法已經被徹底剔除,這個方式對不是特別常用的公共模塊調用能起到精簡代碼的作用,具體使用方法視項目而定。

注意:如果項目中使用了 babel 可能會在 webpack 打包前就將代碼進行轉義導致 tree shaking 不能生效,因為這功能只支持ES6的 import方法,此時只需要使用 babel-preset-env 插件,并修改 .babelrc 文件。

{
    "presets": [
      ["env", {
        "modules": false
      }]
    ]
  }

  • 提取公共模塊
    使用 webpack 自帶的 webpack.optimize.CommonsChunkPlugin 插件進行公共模塊提取。
const path = require('path')
const webpack = require('webpack')

module.exports = {
    entry: {
        ...
        vendor: [
            'lodash'
        ]
    },
    output: {
        filename: 'js/[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
    plugins: [
        ...
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            minChunks: function(module){
                return module.context && module.context.indexOf("node_modules") !== -1;
            }
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: "manifest",
            minChunks: Infinity
        })
    ]
};

entry 增加公共庫文件的chunk,也可將 vue react 這些框架統一寫入此處,在插件處配置 webpack.optimize.CommonsChunkPlugin 的設置,minChunks 接收的類型是 NumberFunction
當為 Number 時表示 chunk 被引用的次數不低于設定值,則會被合入 vendor 模塊;若為 Function,則根據函數返回值進行判斷,module.context && module.context.indexOf("node_modules") !== -1 該配置的含義為僅將 node_modules 目錄下的公共類庫、框架整合進 vendor 模塊內,而忽略項目中被多次調用的自建模塊。

名為 manifest 是個“貨物清單”的配置,是 webpack 中一個特有的配置,目的是將 webpack 中的引導邏輯單獨提取到一個文件中,將其他業務模塊中的引導模塊邏輯剔除,從而減少重復打包的問題,減小單文件容量。


總結

通過對 html-webpack-plugin 的學習,更方便的去構建一張HTML頁面,同時處理靜態資源文件引入問題。對 jscss、圖片等文件在生產環境進行壓縮的方法,接觸了 webpacktree shaking 的使用方法。使用 CommonsChunkPlugin 分離公共模塊的方法,并了解創建一個 manifest 貨物清單文件的意義(分離 webpack 的引導邏輯)。
下章會結合一個 vue 多頁面實例進行構建測試,并引入 DLLPluginDLLReferencePlugin 插件,優化打包速度。


尾巴

tree shaking 這塊卡了很久,一直得不到理想效果,通過排查 才發現是 babel 提前轉義了ES6的 modules 引發的,需要引入 babel-preset-env 取消轉義ES6 modules 才得以解決!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • GitChat技術雜談 前言 本文較長,為了節省你的閱讀時間,在文前列寫作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,710評論 7 110
  • 無意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺,特此分享以備自己日后查看,也希望更多的人看到...
    小小字符閱讀 8,227評論 7 35
  • 前言 WebPack 是什么? WebPack 是什么,WebPack 可以看做是模塊打包機:它做的事情是,分析你...
    Promise__閱讀 1,162評論 3 12
  • 在現在的前端開發中,前后端分離、模塊化開發、版本控制、文件合并與壓縮、mock數據等等一些原本后端的思想開始...
    Charlot閱讀 5,483評論 1 32
  • 三天二夜三座城,生活節奏很快,做了人生多件大事情,下了幾個決擇。有驚喜,有意外,有收獲,有失落。 ...
    小森_b811閱讀 451評論 0 1