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 才得以解决!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容

  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 12,697评论 7 110
  • 无意中看到zhangwnag大佬分享的webpack教程感觉受益匪浅,特此分享以备自己日后查看,也希望更多的人看到...
    小小字符阅读 8,171评论 7 35
  • 前言 WebPack 是什么? WebPack 是什么,WebPack 可以看做是模块打包机:它做的事情是,分析你...
    Promise__阅读 1,128评论 3 12
  • 在现在的前端开发中,前后端分离、模块化开发、版本控制、文件合并与压缩、mock数据等等一些原本后端的思想开始...
    Charlot阅读 5,443评论 1 32
  • 三天二夜三座城,生活节奏很快,做了人生多件大事情,下了几个决择。有惊喜,有意外,有收获,有失落。 ...
    小森_b811阅读 435评论 0 1