[Webpack]webpack学习之旅(第三天)

webpack行程

1. 第一天:webpack安装与基本使用

2. 第二天:如何处理各种格式的文件

3. 第三天:如何生成自定义Html文件

4. 第四天:如何实现开发模式下的配置

5. 第五天:如何实现第三方插件的引入

6. 第六天:如何提取公用代码同时减少冗余代码

7. 第七天:研究vue-cli脚手架源码

 

第三天:如何生成自定义Html文件

 webpack学习之旅的第三天,我们稍作调整。前面两天的行程有点太累,今天我们针对前面的构建流程进行一些优化,比如:我们每次创建新项目都需要手动创建一个Html文件同时手动插入script标签并预先引入构建后的JS资源文件。如果我们每次打包创建的bundle名称加入了hash值 ( 为了缓存的目的 ) ,那么我们就需要手动去修改html文件中引入的JS资源文件名,显然这种方式是不科学的。再比如,我们目前遇到的仅仅是单页面应用,如果我们打包的是多页面应用,比如我们有两个页面,分别对应了两个JS文件入口,那么我们的entry就是两个chunk,构建后的bundle也是两个。难不成我们要手动创建两个html文件,然后分别引入不同的JSbundle文件吗?所以这就引出了我们今天要去参观的html-webpack-plugin插件。

 

1. clean-webpack-plugin

在了解html-webpack-plugin之前,我们先来了解 clean-webpack-plugin 插件。这个插件的作用很简单,就是用来清除我们文件目录的工具。如果使用了hash值,那么每次打包构建后的文件都会不一样,手动清除目录是很繁琐的。我们需要工具来提高效率。使用方法也很简单,第一步肯定是要安装这个插件

npm install clean-webpack-plugin --save-dev

接着我们只需要在webpack.config.js 配置文件的 plugins 选项中添加即可。 凡是插件,需要添加到 plugins 选项中。这个选项接收一个数组,数组中堆满了所有构建需要用到的各种插件。

const cleanWebpackPlugin = require("clean-webpack-plugin")

module.exports = {
    plugins: [
        new cleanWebpackPlugin([
            "dist"
        ], {
            verbose: false
        })
    ]
}

使用方法非常简单,第一个参数paths是文件夹数组,可以指定要删除的目录或者目录下的特定后缀名的文件等等。第二个参数 options 可以指定 root 根目录 ( 默认是 __dirname ) ,也可以指定 verbose ( true表示在终端输出中会显示删除的日志信息 false表示不显示) ,还可以指定 exclude 数组以表示哪些文件需要排除在外。

 

2. html-webpack-plugin

现在正式开始讲解html-webpack-plugin插件的使用。这个插件的目的是帮助我们生成一个包含构建后资源的html文件。那么我们是否需要一个html模板呢? 俗话说是先有鸡还是先有蛋呢?我们想创建一个html文件,那肯定是预先需要一个html壳子的呀,然后插件在这个基础之上帮我们把各种标签如 script meta style title等等信息插入到它应该存放的位置。所以我们就先创建一个最简单的html文件,如下

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
</body>
</html>

只有DOCTYPE head title 和 body,除此之外什么都没有写。接着我们来看插件如何帮助我们生成最终的html文件。

第一步是安装这个插件

npm install html-webpack-plugin --save-dev

接着 webpack.config.js 配置文件中的 plugins配置如下

const htmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    entry: {
        app: path.resolve(__dirname, "./src/index.js")
    },
    output: {
        path: path.resolve(__dirname, "./dist"),
        filename: "[name]-[hash:4].js"
    },
    plugins: [
        new htmlWebpackPlugin({
            template: path.resolve(__dirname, "./index.html"),
            filename: "app.html",
            title: "使用html-webpack-plugin插件自动插入打包资源文件来生成html文件",
            chunks: [ "app" ],
            inject: "body",
            favicon: path.resolve(__dirname, "./favicon.ico"),
            meta: {
                "utf-8": {
                    "charset": "utf-8"
                },
                "viewport": "width=device-width, initial-scale=1.0",
                "X-UA-Compatible": {
                    "http-equiv": "X-UA-Compatible",
                    "content": "ie=edge"
                }
            },
            minify: false
        })
    ]
}

接着简短介绍下options中各个参数的含义

template: 模板文件,就是前面提到的那个壳子

filename:  自动生成的html文件名称,可以指定二级目录

title: html文件中的title标签内容,也就是页面标题,注意,一定要预先在模板中使用 <%= htmlWebpackPlugin.options.title %> 进行占位。

chunks: 指定哪些chunk打包后的文件才能够放入到html文件中,这里就涉及到我们前面提到的应用场景了,两个页面分别对应不同的chunk

excludeChunks: 指定哪些chunk被排除在外,不会添加到html文件中。

inject: 指定页面需要的这些资源文件插入到html文件的哪个部分,比如 true | body 表示插入到 body标签中, head 表示插入到 head标签中, false则表示不要插入,由我开发者来自行插入。

favicon: 指定页面的 favicon小图标文件

meta: 指定页面的meta 信息,参考上图即可。针对meta标签格式不是 <meta name="xxx", content="yyy" /> 这种情形的请使用上面的方式进行定义,如 charset=utf-8等等

minify: 指定页面输出格式,默认可以不设置。当你有html文件输出格式要求时再来设置。具体各个选项可以查看官方文档,给出传送门 html-minifier的git仓库,一般可以设置为如下简单要求:

{
    minify: {
        collapseWhitespace: true,
        removeComments: true,
        removeRedundantAttributes: true,
        removeScriptTypeAttributes: true,
        removeStyleLinkTypeAttributes: true,
        useShortDoctype: true
    }    
}

collapseWhitespace 是否把所有的空白符全部去掉

removeComments 是否把注释去掉

removeRedundantAttributes 是否将多余的标签特性移除,比如input标签默认type=text,比如 a标签的name和id重复了会移除name  

removeScriptTypeAttributes 是否移除 script标签type特性 type="text/javascript"

removeStyleLinkTypeAttributes 是否移除 link style标签的 type特性

useShortDoctype 是否使用更短的DOCTYPE文档声明

 

OK,有了上面这些准备工作,我们在 ./src/index.js 文件中引入CSS样式文件,然后简单添加一句 console.log("hello") 打印语句。通过webpack命令最后构建的日志信息如下

具体源代码可以查看项目git仓库中的 /day3/demo1

 

3. 高级内容

一般来说,对于普通开发者,了解这个插件到这种程度就可以了,可就是有这么一群人,他们会想,为什么我们要预先提供一个html壳子呢?难道就没有办法让插件给我们自动生成一个html壳子呢?于是我在官网上找到了这么一个插件 html-webpack-template 。天呐,还真有这种工具呢,那我们就一起来快快使用吧。

第一步依然是需要先安装这个插件

npm install html-webpack-plugin html-webpack-template --save-dev

接着就是调整我们的 html-webpack-plugin 的 options 选项了,首先 template 参数指定为 这个插件实例 require("html-webpack-template")

接着这个插件给我们丰富了 html-webpack-plugin的 options选项,同时也规定了 inject 参数必须为 false 其他常用参数选项可以参考如下代码

const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
            inject: false,
            template: require("html-webpack-template"),
            title: "使用html-webpack-template生成html文件",
            appMountId: "myApp",
            appMountHtmlSnippet: "<p>我是通过appMountHtmlSnippet插入的内容</p>",
            appMountIds: ["gallery", "panel"],
            bodyHtmlSnippet: "<p>我是插入到body中的p标签</p>",
            lang: "zh-CN",
            window: {
                "userName": "joy"
            },
            chunks: [ "app" ],
            meta: [
                {
                    name: "viewport",
                    content: "width=device-width, initial-scale=1.0",
                }
            ]
        })
    ]
}

常用的扩展参数选项讲解

a. appMountId 表示 会创建这样一个ID的DIV标签,同时将 appMountHtmlSnippet 内容插入其中

b. appMountHtmlSnippet 表示 插入到 appMountId 的 html片段内容

c. appMountIds 表示会创建一系列ID的DIV标签

d. bodyHtmlSnippet 表示会插入到body内部起始位置的 html片段内容

e. lang 指定 html文件的 语言

f. window 定义全局作用域下的变量

g. meta 接收一个数组,默认已经为我们添加了 charset 与 <meta http-equiv="x-ua-compatible" content="ie=edge"> 这两个meta标签。

其余meta可以通过 {name, content}方式插入

h. headHtmlSnippet 表示会插入到head 标签内部起始位置的 html片段内容

通过webpack构建后生成的html文件如下

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta content="ie=edge" http-equiv="x-ua-compatible">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>使用html-webpack-template生成html文件</title>
    <link href="app.css" rel="stylesheet" />
  </head>
  <body>
    <a href="./a.js">我是插入到body中的a链接</a>
    <div id="myApp">
    <p>我是通过appMountHtmlSnippet插入的内容</p>
    </div>
    <div id="gallery"></div>
    <div id="panel"></div>
    <script type="text/javascript">
      window['userName'] = "joy";
    </script>
    <script src="app-3a6b.js" type="text/javascript"></script>
  </body>
</html>

具体源代码可以查看项目git仓库 /day3/demo2

 

4. 后记

第三天,我们只是简化了最终html文件的生成过程,以及通过插件使得我们可以自由定义最终生成的html文件的各种样式。而针对webpack内部对JS资源构建的细节并没有深入介绍。今天介绍的这两个生成html文件的插件可以配合我们第二天介绍的 html-loader 一起使用,比如我们在html模板中引入了一张图片,最后打包时我们会将这张图片的资源引用地址进行修改等等。这部分的源代码及讲解放到后面再说,还是先Mark,因为不是很常用。另外,大家有没有发现我们每次调整源码之后都需要手动再次执行webpack命令,而且最终的 Index.html文件时都是通过file协议打开的,有没有办法实现Http协议打开呢,毕竟我们最终的产品都是通过http协议访问的。大家别急,这就是我们第四天即将前往的景点——webpack-dev-server插件。

posted @ 2019-02-11 17:58  小碎石  阅读(251)  评论(0编辑  收藏  举报