模式
在webpack2和webpack3中我们需要手动加入插件来进行代码的压缩、环境变量的定义,还需要注意环境的判断,十分的繁琐;在webpack4中直接提供了模式这一配置,开箱即可用;如果忽略配置,webpack还会发出警告。
开发模式是告诉webpack,我现在是开发状态,也就是打包出来的内容要对开发友好,便于代码调试以及实现浏览器实时更新。
生产模式不用对开发友好,只需要关注打包的性能和生成更小体积的bundle。看到这里用到了很多Plugin,不用慌,下面我们会一一解释他们的作用。
相信很多童鞋都曾有过疑问,为什么这边DefinePlugin定义环境变量的时候要用JSON.stringify("production")
,直接用"production"
不是更简单吗?
我们首先来看下JSON.stringify("production")
生成了什么;运行结果是""production""
,注意这里,并不是你眼睛花了或者屏幕上有小黑点,结果确实比"production"
多嵌套了一层引号。
我们可以简单的把DefinePlugin这个插件理解为将代码里的所有process.env.NODE_ENV
替换为字符串中的内容
。假如我们在代码中有如下判断环境的代码:
这样生成出来的代码就会编译成这样:
但是我们代码中可能并没有定义production
变量,因此会导致代码直接报错,所以我们需要通过JSON.stringify来包裹一层:
这样编译出来的代码就没有问题了。
自动生成页面
在上面的代码中我们发现都是手动来生成index.html,然后引入打包后的bundle文件,但是这样太过繁琐,而且如果生成的bundle文件引入了hash值,每次生成的文件名称不一样,因此我们需要一个自动生成html的插件;首先我们需要安装这个插件:
npm install --save-dev html-webpack-plugin
在demo3中,我们生成了三个不同的bundle.js,我们希望在三个不同的页面能分别引入这三个文件,如下修改config文件:
我们以index.html作为模板文件,生成home、list、detail三个不同的页面,并且通过chunks分别引入不同的bundle;如果这里不写chunks,每个页面就会引入所有生成出来的bundle。
html-webpack-plugin还支持以下字段:
上面设置title后需要在模板文件中设置模板字符串:
loader
loader用于对模块module的源码进行转换,默认webpack只能识别commonjs代码,但是我们在代码中会引入比如vue、ts、less等文件,webpack就处理不过来了;loader拓展了webpack处理多种文件类型的能力,将这些文件转换成浏览器能够渲染的js、css。
module.rules
允许我们配置多个loader,能够很清晰的看出当前文件类型应用了哪些loader,loader的代码均在demo4中。
我们可以看到rules属性值是一个数组,每个数组对象表示了不同的匹配规则;test属性时一个正则表达式,匹配不同的文件后缀;use表示匹配了这个文件后调用什么loader来处理,当有多个loader的时候,use就需要用到数组。
多个loader支持链式传递,能够对资源进行流水线处理,上一个loader处理的返回值传递给下一个loader;loader处理有一个优先级,从右到左,从下到上;在上面demo中对css的处理就遵从了这个优先级,css-loader先处理,处理好了再给style-loader;因此我们写loader的时候也要注意前后顺序。
css-loader和style-loader
css-loader和style-loader从名称看起来功能很相似,然而两者的功能有着很大的区别,但是他们经常会成对使用;安装方法:
npm i -D css-loader style-loader
css-loader用来解释@import和url();style-loader用来将css-loader生成的样式表通过<style>标签
,插入到页面中去。
然后在入口文件中将index.css引入,就能看到打包的效果,页面中插入了三个style标签,代码在demo4:
sass-loader和less-loader
这两个loader看名字大家也能猜到了,就是用来处理sass和less样式的。安装方法:
npm i -D sass-loader less-loader node-sass
在config中进行配置,代码在demo4:
postcss-loader
都0202年了,小伙伴肯定不想一个一个的手动添加-moz、-ms、-webkit等浏览器私有前缀;postcss提供了很多对样式的扩展功能;啥都不说,先安装起来:
npm i -D postcss-loader
老规矩,还是在config中进行配置:
正当我们兴冲冲的打包看效果时,发现样式还是老样子,并没有什么改变。
这是因为postcss主要功能只有两个:第一就是把css解析成JS可以操作的抽象语法树AST,第二就是调用插件来处理AST并得到结果;所以postcss一般都是通过插件来处理css,并不会直接处理,所以我们需要先安装一些插件:
npm i -D autoprefixer postcss-plugins-px2rem cssnano
在项目根目录新建一个.browserslistrc
文件。
> 0.25%
last 2 versions
我们将postcss的配置单独提取到项目根目录下的postcss.config.js
:
有了autoprefixer
插件,我们打包后的css就自动加上了前缀。
babel-loader
兼容低版本浏览器的痛相信很多童鞋都经历过,写完代码发现自己的js代码不能运行在IE10或者IE11上,然后尝试着引入各种polyfill;babel的出现给我们提供了便利,将高版本的ES6甚至ES7转为ES5;我们首先安装babel所需要的依赖:
然后在config添加loader对js进行处理:
同样的,我们把babel的配置提取到根目录,新建一个.babelrc
文件:
我们可以在index.js中尝试写一些es6的语法,看到代码会被转译成es5,代码在demo4中。由于babel-loader的转译速度很慢,在后面我们加入了时间插件后可以看到每个loader的耗时,babel-loader是最耗时间;因此我们要尽可能少的使用babel来转译文件,我们对config进行改进,
正则上使用$
来进行精确匹配,通过exclude将node_modules中的文件进行排除,include将只匹配src中的文件;可以看出来include的范围比exclude更缩小更精确,因此也是推荐使用include。
file-loader和url-loader
file-loader和url-loader都是用来处理图片、字体图标等文件;url-loader工作时分两种情况:当文件大小小于limit参数,url-loader将文件转为base-64编码,用于减少http请求;当文件大小大于limit参数时,调用file-loader进行处理;因此我们优先使用url-loader,首先还是进行安装,安装url-loader之前还需要把file-loader先安装:
npm i file-loader url-loader -D
接下来还是修改config:
我们在css中给body添加一个小于10k的居中背景图片:
打包后查看body的样式可以发现图片已经被替换成base64格式的url了,代码在demo4。
html-withimg-loader
如果我们在页面上引用一个图片,会发现打包后的html还是引用了src目录下的图片,这样明显是错误的,因此我们还需要一个插件对html引用的图片进行处理:
npm i -D html-withimg-loader
老样子还是在config中对html进行配置:
然鹅,打开页面发现却是这样的:
这是因为在url-loader中把每个图片作为一个模块来处理了,我们还需要去url-loader中修改:
这样我们在页面上的图片引用也被修改了,代码在demo4中。
注
html-withimg-loader会导致html-webpack-plugin插件注入title的模板字符串<%= htmlWebpackPlugin.options.title %>
失效,原封不动的展示在页面上;因此,如果我们想保留两者的功能需要在配置config中把html-withimg-loader删除并且通过下面的方式来引用图片:
vue-loader
最后说一下一个比较特殊的vue-loader,看名字就知道是用来处理vue文件的。
npm i -D vue-loader vue-template-compiler
npm i -S vue
我们首先来创建一个vue文件,具体代码在demo5中:
然后在webpack的入口文件中引用它:
不过vue-loader和其他loader不太一样,除了将它和.vue
文件绑定之外,还需要引入它的一个插件:
这样我们就能愉快的在代码中写vue了。
搭建开发环境
在上面的demo中我们都是通过命令行打包生成dist文件,然后直接打开html或者通过static-server
来查看页面的;但是开发中我们写完代码每次都来打包会严重影响开发的效率,我们期望的是写完代码后立即就能够看到页面的效果;webpack-dev-server就很好的提供了一个简单的web服务器,能够实时重新加载。
首先在我们的项目中安装依赖:
npm i -D webpack webpack-dev-server
webpack-dev-server的用法和wepack一样,只不过他会额外启动一个express的服务器。我们在项目中新建一个webpack.dev.config.js
配置文件,单独对开发环境进行一个配置,相关代码在demo6中:
通过命令行webpack-dev-server
来启动服务器,启动后我们发现根目录并没有生成任何文件,因为webpack打包到了内存中,不生成文件的原因在于访问内存中的代码比访问文件中的代码更快。
我们在public/index.html的页面上有时候会引用一些本地的静态文件,直接打开页面的会发现这些静态文件的引用失效了,我们可以修改server的工作目录,同时指定多个静态资源的目录:
热更新(Hot Module Replacemen简称HMR)是在对代码进行修改并保存之后,webpack对代码重新打包,并且将新的模块发送到浏览器端,浏览器通过新的模块替换老的模块,这样就能在不刷新浏览器的前提下实现页面的更新。
可以看出浏览器和webpack-dev-server之间通过一个websock进行连接,初始化的时候client端保存了一个打包后的hash值;每次更新时server监听文件改动,生成一个最新的hash值再次通过websocket推送给client端,client端对比两次hash值后向服务器发起请求返回更新后的模块文件进行替换。
我们点击源码旁的行数看一下编译后的源码是什么样的:
发现跟我们的源码差距还是挺大的,本来是一个简单add函数,通过webpack的模块封装,已经很难理解原来代码的含义了,因此,我们需要将编译后的代码映射回源码;devtool中不同的配置有不同的效果和速度,综合性能和品质后,我们一般在开发环境使用cheap-module-eval-source-map
,在生产环境使用source-map
。
其他各模式的对比:
plugins
在上面我们也介绍了DefinePlugin、HtmlWebpackPlugin等很多插件,我们发现这些插件都能够不同程度的影响着webpack的构建过程,下面还有一些常用的插件,plugins相关代码在demo7中。
clean-webpack-plugin
clean-webpack-plugin用于在打包前清理上一次项目生成的bundle文件,它会根据output.path自动清理文件夹;这个插件在生产环境用的频率非常高,因为生产环境经常会通过hash生成很多bundle文件,如果不进行清理的话每次都会生成新的,导致文件夹非常庞大;这个插件安装使用非常方便:
npm i -D clean-webpack-plugin
安装后我们在config中配置一下就可以了:
mini-css-extract-plugin
我们之前的样式都是通过style-loader插入到页面中去,但是生产环境需要单独抽离样式文件,mini-css-extract-plugin就可以帮我从js中剥离样式:
npm i -D mini-css-extract-plugin
我们在开发环境使用style-loader,生产环境使用mini-css-extract-plugin:
引入loader后,我们还需要配置plugin,提取的css同样支持output.filename
中的占位符字符串。
optimize-css-assets-webpack-plugin
我们可以发现虽然配置了production
模式,打包出来的js压缩了,但是打包出来的css确没有压缩;在生产环境我们需要对css进行一下压缩:
npm i optimize-css-assets-webpack-plugin -D
然后也是引入插件:
copy-webpack-plugin
web浏览器中的javascript
- 客户端javascript
- 在html里嵌入javascript
- javascript程序的执行
- 兼容性和互用性
- 可访问性
- 安全性
- 客户端框架
window对象
-
计时器
-
浏览器定位和导航
-
浏览历史
-
浏览器和屏幕信息
-
对话框
-
错误处理
-
作为window对象属性的文档元素