Webpack是一个前端资源加载以及打包工具,只需要简单的配置即可实现前端各种工程化的操作。
配置 webpack 说难不难,说简单也不简单,现在几大框架都配备了全家桶,quick-start 项目基本上都已经配置好了基础的 webpack 配置。
虽然能够正常使用,但是,对于各个配置项,并不是很清楚。这几天利用空余时间,理一下几个 loader 和 插件的使用。
关于 loader && loader 的加载顺序
loader 是一个函数,用来把文件转换为 webpack 识别的模块,webpack 本身只能处理加载 javascript,对于 css、image 等资源是无法处理的,而 loader 就是 webpack 开放出来的接口,供用户开发自己的 loader。
loader的使用方式如下
1 | rules: [ |
webpack loader 可以是一个数组,数组的加载方式是从右向左,如上面这个配置,loader 执行的时候,会先使用 url-loader 加载文件,最后用 style-loader 将代码插入文档中。
file-loader/url-loader/tyle-loader/mini-css-extract-plugin loader/vue-loader/css-loader
1.file-loader
文件加载 loader,主要用来加载 import/require 导入的文件
加载比如 css 中 background-image src 的图片等资源
加载导入的字体文件
官方介绍
1 | The file-loader resolves import/require() on a file into a url and emits the file into the output directory. |
2.url-loader
和 file-loader 功能类似,它依赖于 file-loader,file-loader 有的功能它都有
不同之处在于能将导入的文件转为 base64,可以指定文件大小限制,小于某个值的时候将文件转为 base64 的 url
3.style-loader && vue-style-loader && mini-css-extract-plugin loader
1)style-loader 负责将 css 以内联的方式插入文档中
2)vue-style-loader 功能和style-loader 类似,只不过它更专注于 vue 中的 css 提取
3)mini-css-extract-plugin 从名字可以看出,它本身是一个插件,作用是将 css 分离出来,它能将 css 插入文档中,和 style-loader 的区别在于 style 是将 css 内联插入,而它的 loader 通过外部引入的方式将 css 插入文档中。
注意:mini-css-extract-plugin loader 和 vue-style-loader不能同时使用
4.css-loader
加载外部引用 css (@import)以及 从 .vue 文件中提取出来的 css 资源
使用此 loader 只是提取 css 资源,之后还需要用 style-loader 等 loader 将 css 插入 Dom,建议写法:
1 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') |
注意:css-loader如果是用在vue-ssr服务端构建的时候,需要配置exportOnlyLocals,示例如下:
1 | module: { |
5.sass-loader
将 sass/scss 文件编译为 css 文件,需要依赖 node-sass,编译为 css 之后还需要加载 css,所以还得调用 css 的加载 loader,建议写法:
1 | { |
6.postcss-loader
写过 css3 的人应该遇到过很多需要写 css 前缀的情况,这是因为不同浏览器对新特性的支持情况不一样,很多试验性新特性需要加上浏览器前缀才会生效。
postcss 是一个很强大的东东,这里我们只是用它的一个 loader,目的是为了简化 css 写法。
和 autoprefixer 配合使用,会自动给 css 加前缀。
如:
1 | transition: transform 1s |
经过 postcss-loader 会转换为:
1 | -webkit-transition: -webkit-transform 1s; |
用法相对其它loader,需要依赖 autoprefixer,需要多加一个配置文件 postcss.config.js
作用是设置浏览器的范围
1 | // postcss.config.js 文件 |
之后就可以正常使用 postcss-loader 了,同样,此 loader 只是将 css 转换,并不会直接插入到文档中
因此后续还需要用的其它 loader,推荐用法:
1 | { |
注意:这里有个坑
在做的过程中,发现在 index.vue 中 通过 ‘@import url(“../css/index.scss”);’ 导入 index.scss 文件,发现 index.scss 中的 css 属性并没有经过 postcss 转换。
网上查了一下,说是需要给 css-loader 加一个 options:
1 | { loader: 'css-loader', options: { importLoaders: 1 } }, |
但是,经过测试,发现并未生效,看网上的人们说的还真有这么回事儿,但是确实不行(可能是我用的 webpack 版本不一样)。
经过一番折腾,发现只有 @import 加 url 的不行
解决办法:
1 | @import url("../css/index.scss"); |
搞好上面几个 loader,整个 css 的处理基本上就搞清楚了。
接下来就是弄 javascript 的 loader 了。
javascript 还需要 loader 吗?
不是说 webpack 自己能加载 js 吗,为什么还需要 js 相关的 loader 呢?
没错,javascript 本身是不需要 loader 的,但是如果要使用 es6+ 的新特性,就需要用到 loader 了。
我们知道,对于 es6 新特性,不同浏览器支持情况是不一样的,我们使用 loader 的目的就是将 es6 转换为可被浏览器接受的 javascript 语法,似乎跟前面 css 的 postcss-loader 作用一样?
ecmascript 标准制定过程
使用 babel 和 babel-loader,最好是能先对 Ecmascript 的版本和制定有一定的了解。
Ecmascript制定一般会经过如下几个阶段:
1 | stage0:开放阶段,草稿阶段 |
而 babel 的转换具体转换到哪个阶段,则需要自己对其进行相应的配置。
babel
babel,是一个伟大的“发明”。
最近几年 javascript 更新很快,不断有新的特性被提出,不断有的的版本发出。
但是因为客户端本身的复杂性,要想将 js 的新特性运用在浏览器端,并做到很好的兼容性是一个很“艰难”的过程。
各种各样的兼容性已经足够增加成倍的开发成本了。
好在,babel 的出现解决了这个问题,它的出现可以说推进了 javascript 的演进历程。
那么它是如何做到的呢?
babel 原理
babel 是一个‘编译器’,能将高版本的 javascript 编译成低版本的 javascript,以至于浏览器能够正常的使用。
babel 可以单独使用,但是目前更多的还是配合构建工具(如 webpack)来进行使用。
sass-loader 能够将 scss 转换为 css 供浏览器识别。
使用 babel-loader 能够将 es6 转换为 es5 来供浏览器识别。
1 | { |
当然,仅仅这样配置是不够的。因为 javascript 本身比 css 复杂,涉及到更多的版本,包括前面提到的各个 stage 需要兼顾,还得考虑转换之后代码的冗余程度。
具体配置示例如下所示:
1 | // babel.config.js |
Plugins && Presets
plugin 和 preset 告诉编译器如果对代码进行转换。
下面是一些常用 preset 和插件
1 | @babel/core // 核心库,必须安装此依赖 |
1 | @babel/polyfill // 实现目标环境中缺少的功能,包括 core-js 和自定义 regenerator runtime 来模拟完整的 ES2015+ 环境。 |
polyfill 和 runtime 两个模块功能几乎一样,但是实现方法不同
polyfill 会污染全局对象,但是使用简单,如果不是作为公共模块提供给其它应用,可以使用此配置。
runtime 会手动引入 helper 函数
const Promise = require(‘babel-runtime/core-js/promise’) 就可以引入 Promise。
缺点是通过引入的方式,引入的模块不能共享,造成打包之后有很多重复的 helper 代码
所以,babel 又开发了 babel-plugin-transform-runtime 这个模块将代码重写,提取公共方法。
1 | babel-plugin-transform-runtime |
除此之外,还有一些常用的,比如react支持
1 | @babel/preset-react // 转换 jsx 语法 |
typescript 支持,加一个 loader,再加一个 tsconfig 配置文件即可
1 | @babel/preset-typescript // 转换 typescript 语法 用法见后面。 |
typescript 支持,需要加 ts-loader 以及 tsconfig 配置
1 | { |
在根目录下加 tsconfig.json 文件
1 | { |