引言

最近,我们的一个后台系统要改版为基于react + redux + react-router + ant-design 技术栈,切换到当下比较新的技术来实现后台系统;在项目实施过程中,选择了基于react的ant-design组件库,为蚂蚁金服出品。使用该UI组件库,该团队推荐使用其为其配套的内部定制化的构建工具atool-build

推荐使用atool-build工具,因为该工具内部对webpack的一些基本配置内容都做了底层配置,其实atool-build内部定制化了一些基本的配置;

这样,开发者就不在需要一个一个的来配置这些基本的、一般都会用上的配置项,提升了项目构建效率(当然,也可以不使用其推荐的atool-build工具,组件来配置webpack基本配置项);话说回来,虽然atool-build内部定制化了一些基本配置,但是可能不满足开发者的需求,那么我可以在项目根目录中添加webpack.config.js来覆盖该工具内部的一些不满足要求的定制化配置。

本文所说的就是是atool-build定制化的一个配置引起的,下面就描述一下这个问题。

这个坑是由于atool-build内部为后缀为.html文件配置了file-loader导致,具体配置如下:

  1. { test: /\.html?$/, loader: 'file?name=[name].[ext]' }

这个module配置项的意思大家都清楚,即js或者jsx文件引入的html文件,会被抽取为单独的html文件,相对于webpack中output配置项的path路径,file-loader具体的用法可以参考这里

于是否,在webpack中配置一下html-webpack-plugin插件信息,代码如下:

  1. new HtmlWebpackPlugin({
  2. title:'rd平台',
  3. template: 'entries/index.html', // 源模板文件
  4. filename: './index.html', // 输出文件【注意:这里的根路径是module.exports.output.path】
  5. showErrors: true,
  6. inject: 'body',
  7. chunks: ["common",'index']
  8. })

其中,entries/index.html文件的内容如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>RD工具平台</title>
  6. </head>
  7. <body>
  8. <div id="app"></div>
  9. </body>
  10. </html>

然后在应用的入口的js文件中import ./index.html,最后使用npm run build调用atool-build来构建前端代码,生成的index.html出现问题,里面的内容变成:

  1. <head>
  2. <link href="index-9b9df6507771a310f270.css" rel="stylesheet">
  3. </head>index.html
  4. <script type="text/javascript" src="common-1442be5d0c23365a109d.js"></script>
  5. <script type="text/javascript" src="index-9b9df6507771a310f270.js"></script>

根据生成的index.html内容可以看出html-webpack-plugin没有找到指定的模板文件entries/index.html,但是目录结构中确实是有这个文件的。

因此在这种情况下,该插件生成的html内容就是在head中插入抽取的css文件,以及在body中插入入口js文件,其html文档内容为指定模板的文件名index.html;

为啥html-webpack-plugin会出现找不到指定模板文件的情况,而该文件确实是存在的???

百思不得其解,折腾大半天后发现,原来是内部配置的file-loader导致的问题;具体原因,笔者猜测:

  1. 可能是因为file-loader将导入的index.html文件**移动到**指定输出位置后导致`html-webpack-plugin`找不到原有位置的模板文件,从而生成上述情况的index.html文件内容。

于是否,就想到覆盖atool-build内置的file-loader配置,对后缀为.html的文件修改成使用html-loader作为loader,在webpack.config.js中覆盖原有指定配置项具体的代码如下:

  1. if(loader.test.toString() === '/\\.html?$/'){
  2. loader.loader = 'html';
  3. }

然后,在应用的入口js文件中remove掉import './index.html',最后使用atool-build编译构建代码后发现,生成的index.html是期望中的效果。

由此可以说明,file-loader的使用导致了html-webpack-plugin出现了问题。

file-loader与html-loader区别

二者作为loader,其区别还是挺明显的。下面就简述一下二者的区别。

file-loader

file-laoder是对require或者import的指定文件(比如A.html)进行抽取(上面例子中从js中抽取index.html)。

在这一个过程中,抽取文件可以指定具体的目录信息文件名称hash信息后缀信息等等,导入(A.html)的文件在构建编译后不会有该文件A.html的任何痕迹,因为文件被抽取了。

比如,可以将上面index.html文件指定到某个目录下如html目录下,那么file-loader配置中可以这样写:

  1. { test: /\.html?$/, loader: 'file?name=html/[name].[ext]' }

具体的其他配置参考一下其官网给出的例子:

  1. require("file?name=js/[hash].script.[ext]!./javascript.js");
  2. // => js/0dcbbaa701328a3c262cfd45869e351f.script.js
  3. require("file?name=html-[hash:6].html!./page.html");
  4. // => html-109fa8.html
  5. require("file?name=[hash]!./flash.txt");
  6. // => c31e9820c001c9c4a86bce33ce43b679
  7. require("file?name=[sha512:hash:base64:7].[ext]!./image.png");
  8. // => gdyb21L.png
  9. // use sha512 hash instead of md5 and with only 7 chars of base64
  10. require("file?name=img-[sha512:hash:base64:7].[ext]!./image.jpg");
  11. // => img-VqzT5ZC.jpg
  12. // use custom name, sha512 hash instead of md5 and with only 7 chars of base64
  13. require("file?name=picture.png!./myself.png");
  14. // => picture.png
  15. require("file?name=[path][name].[ext]?[hash]!./dir/file.png")
  16. // => dir/file.png?e43b20c069c4a01867c31e98cbce33c9

html-loader

html-loader是将require或者import的html文件转换为html字符串并导出。

在这一过程中,在导出HTML字符串之前,会将html内容中指定元素的一些属性按照attrs=<tag>:<attribute>形式进行更改,一般是一些外部资源的链接替换,默认attrs=img:src

例如,对上面介绍的index.html增加一个img和一个a元素,其内容入下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>RD工具平台</title>
  6. </head>
  7. <body>
  8. <img src="./blue.png"/>
  9. <a href="./blue.png">blue.png</a>
  10. <div id="app"></div>
  11. </body>
  12. </html>

然后对html-loader的配置项配置html文件中的imgsrc属性和a元素的href属性进行变更,其具体的配置如下

  1. //对图片应用url-loader,其中图片小于100byte会使用base64形式,否则抽取一个图片文件
  2. { test: /\.(png|jpg|jpeg|gif)(\?v=\d+\.\d+\.\d+)?$/i, loader: 'url?limit=100' }
  3. if(loader.test.toString() === '/\\.html?$/'){
  4. loader.loader = 'html?attrs[]=img:src&attrs[]=a:href'; //配置img的src属性和a的href属性
  5. }

这样配置编译后生成的index.html内容如下:

  1. <!DOCTYPE html>
  2. <html lang=en>
  3. <head>
  4. <meta charset=UTF-8>
  5. <title>RD工具平台</title>
  6. <link href="index-245b9c326ea3ec1b2089.css" rel="stylesheet">
  7. </head>
  8. <body> <img src=fd0ae22733627f001267a408ec1581ea.png /> <a href=fd0ae22733627f001267a408ec1581ea.png>blue.png</a>
  9. <div id=app></div>
  10. <script type="text/javascript" src="common-56bf69cceda96b513b37.js"></script>
  11. <script type="text/javascript" src="index-245b9c326ea3ec1b2089.js"></script>
  12. </body>
  13. </html>

另外,注意一点:

  1. file-loader不同的是,html-loader会将导入的html内容字符串作为js中一个模块而存在,模块内容挂在module.exports下面。

例如在index.js文件中import './index.html'后,经编译后index.js中该部分的代码如下:

  1. /* 445 */
  2. /***/ function(module, exports, __webpack_require__) {
  3. module.exports = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>RD工具平台</title>\n</head>\n<body>\n<img src=\"" + __webpack_require__(249) + "\"/>\n<a href=\"" + __webpack_require__(249) + "\">blue.png</a>\n<div id=\"app\"></div>\n</body>\n</html>\n";
  4. /***/ },
  5. /* 446 */

由此可以看出:

  • html-loader将html文件作为js的一个模块,模块向外提供编译后的html文件内容字符串,其实可以将其看成一个输出字符串的模块而已。

  • html中的外部链接,如上面的img的src和a的href在html内容字符串所在的模块内部,其实是通过webpack的require形式来加载的,尽管图片是在html文件中通过img形式引入。如上面代码中的__webpack_require__(249),这些require是需要对应的loader来处理的,上面的.png是用url-loader来处理的

由于本人知识有限,文章有什么不正确的地方,请各位批评指正,谢谢!!!

file-loader引起的html-webpack-plugin坑的更多相关文章

  1. webpack入坑之旅(二)loader入门

    这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack 在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...

  2. vue+ vue-router + webpack 踩坑之旅

    说是踩坑之旅 其实是最近在思考一些问题 然后想实现方案的时候,就慢慢的查到这些方案   老司机可以忽略下面的内容了 1)起因  考虑到数据分离的问题  因为server是express搭的   自然少 ...

  3. 如何开发webpack plugin

    继上回介绍了如何开发webpack loader 之后.趁热打铁,来继续看下webpack另一个核心组成:plugin. 下面也和loader一样,让我们一起从基本的官方文档着手看起. loader和 ...

  4. 简单webpack plugin 开发

    重要是学习下怎么开发webpack plugin,同时记录下 插件模型 webpack 是一个插件,可以是javascript class ,或者具名 class 定义apply 方法 指定一个绑定到 ...

  5. 揭秘webpack plugin

    前言 Plugin(插件) 是 webpack 生态的的一个关键部分.它为社区提供了一种强大的方法来扩展 webpack 和开发 webpack 的编译过程.这篇文章将尝试探索 webpack plu ...

  6. webpack入坑之旅(六)配合vue-router实现SPA

    这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...

  7. webpack入坑之旅(五)加载vue单文件组件

    这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...

  8. webpack入坑之旅(四)扬帆起航

    这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...

  9. webpack入坑之旅(三)webpack.config入门

    这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...

  10. webpack入坑之旅(一)不是开始的开始

    最近学习框架,选择了vue,然后接触到了vue中的单文件组件,官方推荐使用 Webpack + vue-loader构建这些单文件 Vue 组件,于是就开始了webpack的入坑之旅.因为原来没有用过 ...

随机推荐

  1. Git使用基础篇(zz)

    Git使用基础篇 您的评价:          收藏该经验       Git是一个分布式的版本控制工具,本篇文章从介绍Git开始,重点在于介绍Git的基本命令和使用技巧,让你尝试使用Git的同时,体 ...

  2. Scrapy框架爬虫

    一.sprapy爬虫框架 pip install pypiwin32 1) 创建爬虫框架 scrapy startproject Project # 创建爬虫项目 You can start your ...

  3. linux_域名映射

    vi /etc/hosts在最后加上ip及映射的域名 192.168.229.111 node001 192.168.229.112 node002 192.168.229.113 node003

  4. unity的三种update

    void FixedUpdate () 固定更新 void Update ()        更新 void LateUpdate()  晚于更新 FixedUpdate () 和 Update () ...

  5. Navicat for MySQL连接出错:1251

    平台:window10 x64+mysql-8.0.15-winx64+navicat_trial_11.1.20.0(PatchNavicat破解) 错误提示:1251-Client does no ...

  6. Element ui 使用 Tree 树形控件

    使用树形控件需要映入 jsx才能运行链接:https://github.com/vuejs/babel-plugin-transform-vue-jsx#usage npm install\ babe ...

  7. mysql之索引查询1

    一 备份数据 备份库: mysqldump:拷贝数据 --database:数据库 基本语法是:mysqldump -h服务器名 -u用户名 -p密码 --database 库名 > 备份路径. ...

  8. 如何将frm文件导入MySql数据库

    只要在mysql的安装文件中找到data文件夹,然后在里面建立一个文件夹,比如test.这个test其实就对应着数据库的名称,所以,你想要起什么样的数据库名称就把文件夹起什么名字. 然后把.frm文件 ...

  9. 2018.11.02 洛谷P2831 愤怒的小鸟(状压dp)

    传送门 状压一眼题. 直接f[i]f[i]f[i]表示未选择状态为iii时的最小次数. 然后考虑现在怎么转移. 显然可以直接枚举消掉某一个点或者某两个点,复杂度O(n22n)O(n^22^n)O(n2 ...

  10. 1-9-假期训练心得(dp+bfs)

    题目一:传送门 思路:就是简单的bfs,注意仔细审题,加上对转弯次数的判断. 题目二:传送门 思路:简单dp,记录每一秒每个位置接到的大饼的数量. 状态转移方程:dp[i][j]=max(dp[i][ ...