webpack行程
1. 第一天:webpack安装与基本使用
2. 第二天:如何处理各种格式的文件
3. 第三天:如何生成自定义Html文件
4. 第四天:如何实现开发模式下的配置
5. 第五天:如何实现第三方插件的引入
6. 第六天:如何提取公用代码同时减少冗余代码
7. 第七天:研究vue-cli脚手架源码
第二天:如何处理各种格式的文件
Webpack学习之旅的第二天,我们将前往Loader目的地一探究竟,了解各式各样的loader都能够处理什么样的文件。
开篇依照惯例,贴上webpack官方文档网址 官方文档首页 与git项目仓库地址 webpack-note
本系列文章是基于webpack3记录的,同时与webpack3配合使用的loader/plugin大家也是要稍微注意一下版本,细节点会在文中有说明。同时也会特别提到webpack4的注意事项,毕竟过不了多久,新的项目肯定会以webpack4进行配置。
在第一天的旅程中,我们学会了webpack的使用方式与最基本的配置文件编写。可是我们的项目会使用到各种各样的文件,如样式文件,图片文件,字体文件等等。那么这些文件webpack又是如何进行打包构建的。这就需要用到我们接下来要讲解的Loader知识了。针对不同的文件,webpack提供了不同的loader,这些loader就是专门用来处理这些文件的。
今天在这里只讲解5个demo,分别对应JS文件,样式文件,字体图片文件,Vue文件和html文件,这些demo都可以在git仓库中的 /day2/ 目录下查看。锚点链接如下
2. 样式文件(CSS, LESS, SCSS, Stylus)
1. JS文件
我们第一天的案例写的就是JS文件,也能正常打包构建,为什么JS文件怎么还需要特殊处理呢?别急,我们在JS文件中编写的ES5语法的代码以及ES6的模块语法确实都能够被webpack打包构建,但是现在都9102年了,现在写JS代码不扔点ES6高级语法,都不好意思说自己是前端工程师。那么这些含有ES6语法的JS文件被webpack打包后,在某些低版本浏览器上是无法正常运行的。所以这就引出了今天要用到的babel-loader。这个loader就是利用babel这个工具将我们写的ES6语法转换为ES5语法。下面就讲讲这个Loader该如何使用。
第一步,安装babel-loader。除此之外,还许需要配合安装几个其他的node包。如 babel-core , babel-preset-env。 由于我们演示用的是webpack3所以安装的babel-core需要保证大版本为6,而babel-loader需要保证大版本为7。babel-loader@8版本已经强制需要babel的版本为7
npm install babel-loader@7 babel-core@6 babel-preset-env --save-dev
如果使用的是webpack4版本,那么安装的babel-loader最新版应该是大版本为8,同时babel-core, babel-preset-env不用安装了,而是安装 @babel/core , @babel/preset-env
npm install babel-loader @babel/core @babel/preset-env --save-dev
贴出不同webpack版本下需要安装的loader与babel等相关安装包的版本截图
同时webpack.config.js需要添加如下配置项目
module.exports = { entry: String, output: Object, module:{ rules: [ { test: /\.js$/, use: "babel-loader", exclude: /node_modules/ } ] } }
首先,module这个配置项是用来指定针对不同模块采用的不同的处理规则,其中rules数组则更加具体的指定了不同文件所需要采用的不同处理规则。每一条规则都是一个object,其中test表示匹配的文件,一般采用正则表达式。 use 则用来指定采用什么样的loader。格式可以是字符串,也可以是字符串数组或对象数组。当你只需要使用一个loader时,如果不需要指定其他options就可以直接简单使用loader名字字符串。 如果需要自定义一些options就可以采用对象数组形式,在对象中指定loader与options。 当你需要使用多个loader时一定是数组形式。exclude 与 Include两个选项分别用来指定 排除在外的模块 与 包含在内的模块。 一般exclude选项都会将 /node_modules/ 文件内的模块排除在外。 有时候为了提高打包构建的效率,可以在include 选项中特别指定打包文件的目录。
其次,配合babel-loader的使用,我们还需要给babel指定一些语法解析的规则。可以在rule里通过options指定,也可以在项目根目录下单独定义 .babelrc 文件,或者在 package.json文件中定义。那么 .babelrc 文件中需要包含哪些信息呢?
一个最简单的.babelrc文件如下 { "presets": "env", "plugins": [" ", " "] }
presets指定了babel将JS高级语法转换为哪个版本的JS语法。以前有ES2015,ES2016, ES2017, Stage-1(Number)等等,比如ES2015意思就是表明我们这个项目能够支持ES2015的语法,那么你babel就帮我把JS高级语法(比如ES2016之后规定的语法)转换为ES2015标准中所定义和支持的语法格式即可。现在babel官方建议只使用env即可,它会根据当前系统环境自行决定应该编译到哪种JS语法的程度即可。
plugins选项是干嘛的呢?我们不是已经能够转换ES6语法了吗。对的,我们通过presets确实可以让babel帮助我们转换ES6高级语法。但是还是会存在一些特殊情况,比如高级API,ES7以及更多草案中的语法。针对高级API,如 promise , set, generator等等,低版本浏览器里面就没有这些核心对象,你怎么办。再比如针对VUE文件中的 ... 等rest/spread语法,低版本浏览器就是不能识别。这时候就需要使用plugins插件给我们打上补丁,以便实现这些特殊功能。
更多具体的Plugins使用,这里先Mark一下,有空再说。
真实案例
具体可以查看git仓库中的 day2/demo1 项目
1. 在 src/mod目录下新建一个a.js
export default {
hello: function(){
document.write("调用modA中的方法hello<br>");
},
bye () {
document.write("调用modA中的方法bye<br>");
}
}
2. 在 src/index.js 入口文件中引入 a.js
import ModA from "./mod/a.js";
document.write("下面显示的文字均为modA模块的方法执行所得<br>");
ModA.hello();
ModA.bye();
3. 新建 index.html 文件并引入 /dist 目录下的 app.js (构建后的文件)
4. 编写 webpack.config.js 文件,同时创建 .babelrc 文件,最后在package.json的scripts脚本中添加 webpack 命令并执行
const path = require("path");
module.exports = {
entry: {
app: path.resolve(__dirname, "./src/index.js")
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.js$/,
use: "babel-loader",
exclude: /node_modules/
}
]
}
}
{
"presets": [
"env"
]
}
2. 样式文件
一个前端项目肯定离不开CSS样式,那么如果我们现在还停留在手写CSS样式的阶段,那就真的是太Out了。现在CSS的预编译工具那么多,大家平时写CSS肯定也是或多或少会使用到其中一种。那么现在就来讲讲如何在JS文件中引入我们的CSS样式文件呢?
按照CSS,LESS,SASS,Stylus等分别讲解需要安装哪些loader并且这些loader常用的配置选项有哪些。
2.1 CSS
解析CSS样式文件需要安装 css-loader style-loader
npm install css-loader style-loader --save-dev
同时添加 css 文件的处理规则 (use数组中的loader顺序按照最后执行的loader放前面,最早执行的loader放后面的方式排列,style-loader 用于JS文件自动生成style标签并将样式放入其中后再插入到HTML文件中)
module: { rules: [ { test: /\.css$/, use: [ "style-loader", "css-loader" ] } ] }
这样一个最简单的CSS文件处理规则就写好了,我们就可以在JS文件中通过 import 方式将其导入。
import "./assets/styles/common.css";
2.2 LESS
解析LESS样式文件需要安装 less 和 less-loader
npm install less less-loader --save-dev
同时添加less文件的处理规则
{ module: { rules: [ { test: /\.less$/, use: [ "style-loader", "css-loader", "less-loader" ] } ] } }
同样也是通过import方式引入less文件即可。
2.3 SASS文件
解析SASS文件需要安装 sass-loader node-sass
npm install sass-loader node-sass --save-dev
同时添加 sass文件的处理规则 (sass文件有两种后缀格式 .scss .sass 我们常用的就是 .scss 格式 )
{ module: { rules: [ { test: /\.(scss|sass)$/, use: [ "style-loader", "css-loader", "sass-loader" ] } ] } }
同样也是通过 import 语法将 .scss文件引入。
2.4 Stylus 文件
Stylus这种预编译CSS的文件格式为 .styl 解析这种文件同样需要安装 stylus-loader
npm install stylus-loader --save-dev
同样添加 .styl 文件的处理规则,也同样通过 import 语法引入 .styl 文件
{ module: { rules: [ { test: /\.styl$/, use: [ "style-loader", "css-loader", "stylus-loader" ] } ] } }
具体各种loader的配置先mark 放到后面在补充。
实战案例可以参考git仓库中的 /day2/demo2/
3. 字体和图片文件
既然使用到了样式文件,那么必不可少的就是样式文件中可能引用的各种图片资源和字体图标资源啦。那么我们又该如何处理这些文件呢?这时我们的 file-loader 和 url-loader 就派上用场啦。
首先我们需要先安装这几个loader
npm install file-loader url-loader --save-dev
file-loader可以针对import或require加载的文件进行输出方面的处理,url-loader可以对文件进行base64编码处理。
接着针对字体文件和图片文件可以按照如下配置方式进行处理
module.exports = { module: { rules: [ { test: /\.(jpeg|gif|jpg|svg|png)$/, use: [ { loader: "url-loader", options: { limit: 3000, fallback: { loader: "file-loader", options: { name: "[name]-[hash:4].[ext]", outputPath: "./assets" } } } } ] } ] } }
配置文件说明:
1. 先使用url-loader针对图片进行base64编码,限制大小为3000byte即3KB,如果图片大小超出这个限制则使用fallback指定的file-loader进行处理
2. file-loader配置项包括 name 和 outputPath 分别指定输出图片的名称 与 输出路径
其中 [name] [hash:4] [ext] 分别表示 图片原始文件名,图片打包构建后的hash码保留4位,图片后缀名
outputPath表示在 output 配置项中的path路径基础之上的输出路径。
同理,针对字体文件我们也可以使用相同的loader及配置项,不同之处在于 test 匹配的文件后缀名不一样。
test: /\.(eot|svg|ttf|woff2?)$/
补充说明,一般情况下使用file-loader处理我们的图片就够用了,但是有时候我们可能还需要对图片进行一些其他特殊处理,包括图片压缩优化处理,多图片拼接成雪碧图等等。这部分内容也先mark一下,放到后面再说。
上面的实战案例可以参考git仓库中的 /day2/demo3/
截图中可以看到.eot字体文件大于5000byte 则会单独以文件形式输出,而其他字体文件则以base64编码格式被打包在app.js文件中
4. Vue文件
针对Vue文件的解析非常简单,需要安装 vue-loader 和 vue-template-compiler
npm install vue-loader vue-template-compiler --save-dev
大家现在去安装vue-loader肯定安装的是版本15,从版本15开始需要在配置文件中特别指定vue-loader下的VueLoaderPlugin
const VueLoaderPlugin = require("vue-loader").VueLoaderPlugin;
然后针对 .vue文件编写相应loader处理规则
module.exports = { module: { rules: [ { test: /\.vue$/, use: "vue-loader" } ] }, plugins: [ new VueLoaderPlugin() ] }
这样一个最简单的vue文件处理的webpack配置文件就写好了,具体vue代码可以参考git仓库项目 /day2/demo4/
更多关于vue-loader的配置项可以查看官方文档,给出传送门地址Vue-loader配置文档
后面有时间也会在这里详细讲述vue-loader配置项中常用参数的作用与案例讲解,先mark一下。
5. html文件
其实说到html文件的处理,更多的还是第三天我们要去的目的地,如何生成自定义的html文件。但是偶尔还是会出现需要我们单独处理html文件的情形。比如: 我在html文件中定义了img标签并且引入了一个图片文件。按照我们前面讲解的内容,如果我们在定义时使用的是源图片地址,那么这个图片文件引入的路径在最终打包时并不会发生变化,也就是不会自动引入图片打包后的路径地址。那么除了我们手动修改路径外,有没有什么办法能够帮助我们自动完成呢?答案肯定是有的。这就是我们html-loader的作用。
首先依然是需要安装html-loader
npm install html-loader --save-dev
接着我们创建入口 index.js文件,该文件引入了一个html文件中的标签内容,作为新创建的DOM节点中的内容。
import "./index.css"; import html from "./part.html"; const galleryNode = document.createElement("div"); galleryNode.className = "gallery"; galleryNode.innerHTML = html; document.body.appendChild(galleryNode)
于是我们需要创建 part.html 文件,现在我们只在这个文件中添加一个 Img标签并引入对应路径的图片。
<img src="./1.jpeg">
而样式文件只是定义了 .gallery 样式,以保证图片宽度不至于很大。
.gallery{ width: 300px; } .gallery img{ display: block; width: 100%; }
最后需要调整我们的webpack配置文件,给其中添加一段处理html文件的rule
module: { rules: [ { test: /\.(jpg|jpeg|png|gif)$/, loader: "url-loader", options: { limit: 5000, fallback: { loader: "file-loader", options: { name: "[name]-[hash:4].[ext]", outputPath: "./assets/image" } } } }, { test: /\.html$/, use: "html-loader" } ] }
html-loader的options非常简单,就是 <tag> : <attribute> 的格式,默认值就是 img : src 也正因为如此,大部分使用html-loader的情形都是针对html中的图片资源进行解析。
6. 后记
我们第二天的行程非常累,观看的景点loader非常多,另外,每个景点loader的options细节也非常丰富,想要对这些options非常熟悉,就需要我们平时多动手,将这些options一个个的加以练习,动手才能学会每一个loader的每个options。当然,本篇内容目前也只是对loader做了基本介绍,很多options都还没有花时间给大家讲解,有兴趣的同学可以自行先去各个loader的官网或者github仓库去查看readme.md文件或文档。今天在介绍每个loader并编写相关代码时,都是预先定义好了一个html文件,然后在其中引入构建后的js文件。这样很繁琐,有没有办法让webpack帮助我们自动生成html文件并且将构建后的JS文件添加进去呢?这就是我们第三天行程要去的地方,一个好用的webpack插件html-webpack-plugin。