前言
Webpack 4 + Babel 7 打造 ES6+ 前端环境。
如果对配置过程无兴趣或想直接下载模版,快速开始 ES6+ 编程,可直接跳过参考 模版下载 。
第一步,创建基本目录
src 目录,用于存放自己写的源码。
1 | demo |
第二步,安装依赖
1.创建 package.json
文件
1 | # demo 项目文件夹内 |
2.安装 webpack
和 webpack-cli
1 | npm i webpack webpack-cli -D |
i
:install
安装命令;-D
:--save-dev
开发依赖;
注:webpack 3 中不需要安装 CLI ,webpack 包已集成,但在 webpack 4 中已经分开管理,需要分开安装。上述命令安装的版本为 webpack 4,指定版本安装可以执行 npm i webpack@3 -D
。
3.安装 babel 相关
1 | npm i babel-loader @babel/core @babel/preset-env -D |
1 | npm i @babel/polyfill -S # 注意,运行时依赖 -S(--save) |
babel-loader
: babel 编译器的 webpack loader;@babel/core
: babel 7 的核心代码;@babel/preset-env
: babel 智能预设,转换 ES6 语法;@babel/polyfill
: 环境垫片,转换 ES6 API 等;
第三步:配置
1. webpack 配置
根目录下添加 webpack.config.js
配置文件,配置入口文件和导出设置:
1 | const path = require('path') // 使用 Node 的 path 模块,不需要额外安装,处理绝对路径 |
以上配置包括:
- 指定入口文件
- 打包导出设置(目录和文件名)
- 使用 babel-loader 编译 JS 文件
详细 webpack 配置项可参考官网 webpack.config.js ,十分详细。
2. babel 配置
babel 7 有三种配置方式,任选一种:
- 添加
babel.config.js
配置文件(官方推荐) - 添加
.babelrc
配置文件 - 直接在
package.json
添加配置
1)根目录下添加 babel.config.js
配置文件:
1 | module.exports = { |
2)根目录下添加 .babelrc
配置文件:
1 | { |
3)直接在 package.json
添加配置,键名babel
:
1 | { |
三种配置方式任选一种,默认编译 ES2015 + 语法。
配置说明:
关于 @babel/polyfill :
Babel 转换 ES6 代码,仅仅只是转换 ES6 的语法,诸如 let
、const
、箭头函数、模版字符串、解构赋值等。并不会转换 ES6 的新 API,如Generator
、Set
、Maps
、Proxy
、Reflect
、Symbol
、Promise
等全局对象,还有如 Array.from
等 ES6 新增方法。
如需使用新 API 并且兼容旧浏览器时,就需要使用到 polyfill ,原理则是向全局注入这些新 API,即相当于直接调用写好的一个功能函数集,只需引用即可。注意:使用 polyfill 会污染全局环境,如是写类库的同学,请使用 transform-runtime ,参考 babel-plugin-transform-runtime。
@babel/polyfill 使用有如下几种:
直接import
或 require
引用:
1 | // require("@babel/polyfill"); |
webpack.config.js
多入口引用 polyfill :
1 | module.exports = { |
以上两种的缺点:引入了整个 polyfill 包,没用到的 API 也打包进去(不推荐)。
推荐做法参考以下 关于预设的配置 useBuiltIns 。
关于预设的配置 useBuiltIns :
根据官方文档 babel-polyfill :
With webpack, there are multiple ways to include the polyfills:
- When used alongside
@babel/preset-env
,
- If
useBuiltIns: 'usage'
is specified in.babelrc
then do not include@babel/polyfill
in eitherwebpack.config.js
entry array nor source. Note,@babel/polyfill
still needs to be installed.- If
useBuiltIns: 'entry'
is specified in.babelrc
then include@babel/polyfill
at the top of the entry point to your application viarequire
orimport
as discussed above.- If
useBuiltIns
key is not specified or it is explicitly set withuseBuiltIns: false
in your .babelrc, add@babel/polyfill
directly to the entry array in yourwebpack.config.js
.
当 @babel/polyfill
与 @babel/preset-env
搭配时,babel 预设配置添加 useBuiltIns: "usage"
可以让 polyfill 不需 import
,也会自动将代码里已使用到的,且 browserslist 环境不支持的垫片导入,可以避免打包后文件过大。
注意:添加了 useBuiltIns: "usage"
就不需要再像上述两种引用 polyfill 包了,babel 会自动将 polyfill 自动按需引用打包。而且需要指定 core-js 版本,如上文配置一样。
1 | // babel.config.js |
指定浏览器:指定浏览器兼容编译,会很大程度影响编译文件大小,也有两种配置方式。= =
presets
添加targets
指定浏览器;- 配置
browserslist
(推荐)
Babel 编译优先看有没有配置
targets
,再看是否配置browserslist
,都没有就默认编译所有 ES2015 + 代码。
1)presets
添加 targets
,以 babel.config.js
为例:
1 | module.exports = { |
or targets
传入对象,指定浏览器最低版本。
1 | module.exports = { |
注意:如果是在
.babelrc
下配置targets
,所有键名记得加双引号 ““,.babelrc
其实就是个 JSON 文件,写法必须符合 JSON 格式。
2)配置 browserslist
列表
添加 .browserslistrc
配置文件:
1 | > 0.25% |
or 直接在 package.json
添加配置,键名browserslist
:(推荐)
1 | { |
总结 Babel
配置,babel.config.js
添加预设配置,package.json
添加 browserslist
。
3. 配置命令脚本
修改 package.json
文件中的 “script”
,添加 webpack 打包命令;
1 | { |
第四步:运行
如果你只是单纯的想要有个 ES6 编码环境,并编译打包 JS 代码,那到这里就算完成啦,接下来就是愉快的敲 ES6 + 代码啦。
比如:
1 | demo |
模块代码文件 util.js
:
1 | export function add(a, b) { |
入口文件 main.js
:
1 | import { add, square } from './js/util' // 引入模块 .js后缀可省略 |
运行编译打包:
不压缩丑化代码,运行开发模式打包:
1 | npm run dev |
或压缩丑化代码,运行生产模式打包:
1 | npm run build |
运行完毕后,目录会出现一个 dist
目录:
1 | demo |
main.bundle.js
即为编译打包好的文件。
其它配置
如果不仅仅只是需要 JS 环境,且需要前端 HTML 支持,或打包 css 文件等。可以按需如下操作:
html-webpack-plugin
这个插件会根据提供的 src/index.html
为模版,将打包好的js
文件通过 script
标签注入到 HTML 文件中,并将生成的 HTML 文件输出到 dist 目录中,不需要手动添加。
安装:
1 | npm i html-webpack-plugin -D |
配置 webpack.config.js
:
1 | const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件 |
更多配置查看官方文档 => html-webpack-plugin 。
src/index.html
创建 HTML 模版:
1 |
|
npm run build
:
1 | dist |
html-webpack-plugin
生成的 HTML ,js 文件自动被引入。
1 |
|
webpack-dev-server
这个插件可以在创建本地服务器,热更新等,默认根目录为打包输出目录 dist ,也可以自己配置。
安装:
1 | npm i webpack-dev-server -D |
配置 package.json
,添加 webpack-dev-server
命令 :
1 | { |
以上start
命令是以 webpack-dev-server
命令运行,自动打开 localhost
页面,修改源码保存会自动编译,并刷新页面。
1 | npm run start |
此时,浏览器会自动打开 localhost:8080
页面,页面即是 dist 文件夹下的 index.html
,现在就可以直接修改 html、js 源码,一保存代码会自动编译,页面也会自动刷新。
--open
相关配置及其它配置也可直接在 webpack.config.js
中指定,就不需要在命令中指定 --open
等命令了,键名 devServer
:
1 | module.exports = { |
注意,热模块更新(HMR)需要搭配 webpack 内置插件 HotModuleReplacementPlugin
使用,关于热模块更新下文详解 热模块更新。。
更多配置查看官方文档 => webpack-dev-server 。
CSS 相关
加载 CSS 文件需要使用到 css-loader
、style-loader
。
1 | npm i style-loader css-loader -D |
css-loader
: 解析 css 文件中的@import
和url()
语法,根据文件关系将 CSS 转化成 CommonJS 模块。style-loader
: 将css-loader
打包好的 css 以<style>
标签输出在<head>
中。
webpack.config.js
添加模块规则:
1 | module.exports = { |
main.js
引入 css 文件:
1 | import './css/style.css' |
npm run start
即可以在页面中看到引用的样式啦。
注:使用 style-loader
并不会生成独立 css 文件,css 样式会被打包进 main.bundle.js
文件中,打开dist/index.html
页面时样式才会被 JS 写入 <head>
下的 <style>
标签中。
使用 css 预编译器
- Sass :安装
sass-loader
和node-sass
,文档; - Less :安装
less-loader
和less
,文档; - Stylus : 安装
stylus-loader
和stylus
。
以书写 scss
文件为例,先安装依赖:
1 | npm i sass-loader node-sass -D |
webpack.config.js
添加模块规则:
1 | module.exports = { |
main.js
引入 scss
文件:
1 | import './scss/style.scss' |
使用 postcss-loader
PostCSS 是一个 CSS 处理工具,和 Sass 等不同的地方可以用不同的插件扩展 css 的特性,包括给 CSS 自动加前缀、压缩 CSS、使用下一代 CSS 语法等。
这里使用 autoprefixer
和 cssnano
插件来自动加 css 浏览器前缀和压缩 css:
1 | npm i postcss-loader autoprefixer cssnano -D |
webpack.config.js
添加模块规则:
1 | module.exports = { |
postcss-loader 的配置也可以是单独的配置文件 postcss.config.js
,详情查看文档 postcss-loader。
atuoprefixer
会根据上文中提到的 babel 配置 中的 browserslist
浏览器列表来添加前缀,本例是在 package.json
添加了浏览器列表:
1 | { |
注意:
- 如果同时有使用 css 预编译器 loader 的话如
sass-loader
,postcss-loader
应该在sass-loader
之前,css-loader
之后。 - 配置其他 loader 的同时,注意
css-loader
要指定importLoaders
配置,指定使用 css-loader 时前面还需要经过几个 loader 先。不然在 css 文件中使用@import
再引入其他 css 时会直接跳过其他 loader,问题如下:
原始 Css :
1 | src |
1 | /* style.css */ |
style.css
通过 @import
引入 other.css
。
1 | /* other.css */ |
npm run start
后打开 HTML 你会发现:
1 | <style> |
明显只有 style.css
中的样式经过了postcss-loader
。
other.css
虽然被引入了,但是并没有经过 postcss-loader
的压缩和加前缀。所以,应该给 css-loader
指定 importLoaders
,告诉 css-loader
处理引入 css 时应该先经过几个 loader。同理,如果同时使用了 postcss-loader
和 sass-loader
则 importLoaders
应该设置为 2 。
指定 css-loader
的 importLoaders
后的运行结果(前缀+压缩):
1 | <style> |
CSS 代码文件分离
上述配置后,打包无论多少 css 文件,都会被 css-loader
打包进 main.bundle.js
文件中,再由 style-loader
输出至 <head>
的 <style>
标签中。如果要将 css 代码文件分离,可以使用 webpack 提供的其他插件。
注意:由于翻译的滞后性,在 webpack 中文文档中,有些文档如 sass-loader 中文 中,建议我们使用 extract-text-webpack-plugin
插件来 css 代码分割,中文文档中的 ExtractTextWebpackPlugin 中文 也没有提醒 webpack 4 中并不可用,但是,你阅读英文原文 ExtractTextWebpackPlugin 英文 ,有如下提醒:
:warning: Since webpack v4 the
extract-text-webpack-plugin
should not be used for css. Use mini-css-extract-plugin instead.
在中文文档中,你甚至找不到 mini-css-extract-plugin
这个插件(= = !!!),所以尽量阅读英文文档,在用 webpack 4 时我们应该使用 mini-css-extract-plugin
来进行代码分离。
安装:
1 | npm i mini-css-extract-plugin -D |
webpack.config.js
替代 style-loader
模块规则:
1 | // 1.引入插件 |
filename
: css 文件输出目录及名字;publicPath
: 主目录地址,这与 filename 指定的文件目录有关,因为上述配置了输出文件放在dist/css
目录中,所以publicPath: "../"
就是将主目录拉回到dist
目录,即在输出时给资源自动加上../
,这样 css 中引入资源才不会有路径问题。hmr
: 热模块更新,开发模式下才使用,关于热模块更新下文详解 热模块更新。
npm run build
后 dist
文件夹:
1 | demo |
输出的 main.css
同样会自动以 <link href="css/main.css" rel="stylesheet">
自动写入 index.html 的 <head>
中,无需自己手动引用 css 文件。
加载静态资源
webpack 除了 JS 以外,所有的其他格式的文件都需要响应的 loader 来解析,才能做到被 webpack 处理打包。加载图片、字体需要 file-loader,加载数据需要 csv-loader 和 xml-loader 。
加载图片
建议使用 url-loader 和 file-loader 配合。
安装:
1 | npm i url-loader file-loader -D |
url-loader
: 可以将图片转换成 base 64 。file-loader
: 图片以文件形式输出。
webpack.config.js
添加模块规则:
1 | module.exports = { |
loader
: 配置url-loader
即可,超过大小的图片会自动使用file-loader
;limit
: 限制图片大小,单位 bite;超过这个输出文件,小于转成 base 64,不宜过大;name
: 输出文件名字,可以指定目录,不指定所有图片会被放在 dist 目录下。- 占位符
[name]
: 原始文件名; - 占位符
[hash:8]
: 图片对应哈希值,8 指位数。[hash] 默认是 32 位; - 占位符
[ext]
: 文件后缀;
使用:
1 | demo |
入口文件 main.js
引入 style.css
, css 内容:
1 | body { |
npm run build
后:
1 | demo |
main.css
如下:
1 | body { |
相对路径及引用都正确被正确识别。
热模块更新
热模块更新(HMR)在上文的 webpack-dev-server 和 CSS 代码文件分离 中都有提到,如上述在不配置 HMR 的情况下,已经可以做到一修改保存源码,页面自动刷新了。但这样可能会面临这样的问题,比如修改的 JS 或 CSS 代码是在页面中需要 N 步操作后才会显示的,这样我们每修改代码,页面自动刷新,就又要经历 N 步之后才能看到是否正确,尤其是在修改 CSS 样式时。
HMR 就是解决这样的问题,可以保持页面不刷新,只刷新修改的源码部分。
第一步:webpack-dev-server
启动 HMR
命令行直接添加 --hot
1 | { |
或抽离 webpack-dev-server
配置到 webpack.config.js
,键名 devServer
:
1 | { |
1 | // webpack.config.js |
第二步:使用 webpack
内置插件 HotModuleReplacementPlugin
1 | // webpack.config.js |
关于 CSS 热模块更新,如果是使用 style-loader
,那如上配置即可做到热模块更新了,如果是使用 MiniCssExtractPlugin
插件对 CSS 代码文件分离的话,需要在 loader 的配置加上 hrm: true
。
1 | // webpack.config.js |
此时,npm run start
后页面自动打开,修改 JS 或 CSS 后保存,页面就不会自动刷新,而是只有修改的模块代码被更新。
模版下载
模版除了 css 预编译器没有配置外,其它都一致,如需要配置 css 预编译器,安装相应 loader ,配置相应的模块规则即可,参考 #使用 css 预编译器。
Github : https://github.com/VincentTV/ES6
目录说明
1 | ES6 |
下载
1 | git clone https://github.com/VincentTV/ES6.git |
安装依赖
1 | cd ES6 |
1 | npm install |
运行
1 | npm run start |
开始 ES6 编程。
编译输出
1 | npm run build |
1 | ES6 |