babel 的目的就是为了解决浏览器的自身对于 es 语言的差异性而带来的一款工具,有了 babel 就首先不用担心旧浏览器不支持 es 语言这件事,其实最重要的不是支持,而是解决差异性,这种差异性不仅介于浏览器之间,对于 node 这样的环境也会存在这样的问题,各个 node 版本对于 es 的支持,或者对于 es 的一些尚未提交的草案的支持都是不同的,所以不论是浏览器下还是 node 下都需要到使用 babel 的场景
Error: Cannot find module '@babel/core'
babel-loader@8 requires Babel 7.x (the package '@babel/core').
If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7'.
前阵子自己开坑写了个 npm 开源的交互组件,按照 webpack 的配置流程走了一遍,打包遇到了各种坑。根据命令行的报错逐个排查,发现 babel 升级到 7.x 之后有坑。为了更好的记录遇到的问题以及解决方案,这里以 webpack4.x 的全套配置流程为方式重新梳理一遍
webpack 和 babel 浅析
在梳理配置流程之前我们先来大致过一下 webpack 和 babel 的基础理论,如果想更详细的了解,可以去查阅一下 webpack 官方文档 和 Babel 官方文档
webpack
也就是说,一切静态资源,皆可打包。webpack 可以说是现代前端发展的基石
那为什么需要 webpack 来打包呢? webpack 到底发挥的是什么作用?
webpack 可以通过分析项目结构,找到 JavaScript 模块以及其它一些浏览器不能直接运行的扩展语言( Scss , TS 等),并将其打包为合适的格式以供旧浏览器使用
以往的前端技术,是用jQuery、html、css等来开发静态页面;而现在的,我们讲的都是 MVVM 框架,数据驱动界面,webpack 可以将现在 js 开发中的各种新型有用的技术集合打包
在如今功能丰富的页面下,都有着复杂的 JavaScript 代码和一大堆依赖包,为了简化开发的复杂度,前端社区出现了很多有益于提高开发效率的方法
比如我们熟悉的模块化开发,把复杂的程序细化为小的文件;scss / less 等 css 预处理器
这些开发方式都需要额外的处理才能让浏览器识别,而手动处理又是非常繁琐的,这就为 webpack 这类工具的出现提供了需求
babel
Babel 可以转换 JSX 语法,可以将 ES6 的代码转换为 ES5
babel 的目的就是为了解决浏览器的自身对于 es 语言的差异性而带来的一款工具,有了 babel 就首先不用担心旧浏览器不支持 es 语言这件事,其实最重要的不是支持,而是解决差异性,这种差异性不仅介于浏览器之间,对于 node 这样的环境也会存在这样的问题,各个 node 版本对于 es 的支持,或者对于 es 的一些尚未提交的草案的支持都是不同的,所以不论是浏览器下还是 node 下都需要到使用 babel 的场景
尤其是现在 Javascript 主要是用 ES6 编写的,为了更好适应各种旧浏览器,我们需要进行转换处理,这个转换的步骤也就是 transpiling(转译)
webpack 不知道如何进行转换但是有 loader (加载器),也就是转译器
babel-loader 是一个 webpack 的 loader (加载器),用于将 ES6 及以上版本转译至 ES5
使用 loader 之前,我们需要安装一堆依赖项,尤其是:
webpack 4 变化
这里主要看看我们用的比较多的两则变化:
webpack 4 既不必须定义 entry point(入口点) ,也不必须定义 output file(输出文件)
entry point (入口点):webpack 寻找开始构建 Javascript 包的文件 output file (输出文件):webpack 构建完成输出 Javascript 包的文件
但是从 webpack 4 开始,这两个属性不是必须定义的,它有一个默认值,会将 ./src/index.js 作为默认入口点, ./dist/main.js 作为默认输出模块包
当然,我们也可以覆盖默认 entry point(入口点) 和 默认 output(输出) ,只需要在 package.json 中配置它们
或者
webpack 4 引入了 production(生产) 和 development(开发) 模式
拥有两个配置文件在 webpack 中是常见模式,但在 webpack 4 中,我们可以在没有一行配置的情况下完成,仅仅只需要在 package.json 中填充 script 部分
然后运行
打开 ./dist/main.js,会发现有一个没有压缩的 bundle(包)文件
接着运行
再次打开 ./dist/main.js,没错,bundle(包)压缩了!
production mode (生产模式) 可以开箱即用地进行各种优化。 包括压缩,作用域提升,tree-shaking 等 development mode (开发模式) 针对速度进行了优化,仅仅提供了一种不压缩的 bundle
环境搭建
这里使用 npm 来安装 webpack
在 webpack3 中, webpack 和 cli 是在同一个包中,但在第4版中,为了更好的管理,已经将两者分开
初始化项目和配置
部署配置
修改我们项目的 package.json ,使用
npm run build
启动 webpack我们在项目实战中应该很熟悉,类似于 vue-cli 或者是 umijs 这样的脚手架在打包的时候都会通过配置自动生成项目,通常都是在 src 文件夹下进行项目的开发,然后运行
npm run build
打包并生成我们的 dist 文件比如我们在 src 目录下新建一个 index.js 文件,写上
然后运行
npm run build
,会发现新增了一个 dist 目录,里面存放着 webpack 打包好后的 main.js 文件配置流程
回想我们之前做过的项目,一般会打包 src 下的什么文件呢?
下面就跟着上述几点来依次在 webpack 的 webpack.config.js 中进行配置,以 commonJS 模块化机制向外输出
html 配置
这里就不使用默认配置了,自行定义好入口 entry 和出口 output 。通俗的理解就是,webpack 相当于一个工厂,进入相当于把各种各样的原料放入我们的工厂,然后工厂进行一系列的打包操作,将打包好的东西向外输出,就可以出售了(上线)
HTML 打包需要安装插件
html-webpack-plugin
,它将会创建一个 index.html 文件,有了这个插件,我们就可以不用手动创建一个 index.html 文件了然后在 webpack.config.js 中引入
配置好后,在终端输入
npm run build
后 webpack 将 html 打包好并且自动将 js 引进来了在 dist 目录下启动本地服务器测试一下,运行
http-server
,然后在浏览器中打开一个 ip 地址的 8080 端口,就可以在浏览器中看到我们的 Hello World 了,也就是我们上线的页面css 配置
在我们的项目应用中,往往为了提高编程效率,使用一些预编译器,比如 stylus 、less 、sass 等,这里主要以 less 和 css 为例进行说明
在 src 下新建 index.html 、main.css 、style.less 文件
在 index.js 中引入
然后安装文件 css-loader 、 sass-loader 和 sass
因为想让 css 在 dist 目录下和 HTML 分离,所以这是还需引入 extract-text-webpack-plugin
需要注意的是,这里有一个坑,因为 extract-text-webpack-plugin 最新版本为 3.0.2 ,这个版本还没有适应 webpack 4 的版本
解决办法:使用 4.0 beta 版
会下载到 extract-text-webpack-plugin@4.0.0-beta,安装好后,我们开始配置webpack.config.js文件
但是即便是使用 extract-text-webpack-plugin@4.0.0-beta 代替,还是会有一些问题,所以可以用另一个插件来代替,webpack4 可以使用 mini-css-extract-plugin 这个插件来单独打包 css
打包之后 http-server , 发现我们的样式已经生效了,.less 的文件也被编译到 .css 文件中了,并且 css 部分已经从 html 中分离出来
js 配置
为了让更多的旧浏览器适应 es6 的开发语法,需要引入 babel 来把 es6 的代码编译为 es5 。在根目录下新建 .babelrc
在 index.js 中添加代码
然后安装文件
接下来在 webpack.config.js 中配置
这里会出现一个大坑,因为我们的 babel 已经升级到了一个大版本 - 7.x
没找到 @babel/core ,这里把 babel-core 卸载,并安装 @babel/core
同理,也需要将 babel-preset-env 卸载后重新安装,最终安装好的文件是
babel 舍弃了以前的 babel-- 的命名方式,改成了 @babel/-
修改完依赖和 .babelrc 文件后就能正常启动项目了
为 React 项目配置 webpack 4
安装 React :
因为前面已经安装了
babel-loader
,@babel/core
,@babel/preset-env
, 所以只需安装babel-preset-react
, 同上面一样的情况,在 babel 7 中,我们需要安装@babel/preset-react
再次强调:babel 7 使用了 @babel 命名空间来区分官方包,因此以前的官方包 babel-xxx 改成了 @babel/xxx
修改 webpack.config.js 和 .babelrc 文件
然后在 src 目录下新建一个 App.js 的 react 组件
接下来在 index.js 文件中 import(导入) 组件
在 index.html 中添加代码
再次构建
npm run build
即可如果想详细了解可以查阅这篇文章 React 教程:如何使用 webpack 4 和 Babel 构建 React 应用(2018)
图片资源的配置
在src目录下新建一个assets文件,里面放置图片
安装依赖文件
然后在 webpack.config.js 中添加配置
然后在 index.js 文件中引入
然后在 index.html 中添加代码
别名(@)的配置
在 src 目录下新建一个文件夹 utils , 然后在 utils 中新建文件 format.js
如果我们要在 src/index.js 中引入这个 format.js 文件呢,理所当然是不是想这么写
这样写确实没错,但如果想使用别名代替呢?比如在 vue-cli 项目中常用的 @ 一个文件路径,其意思就是在 src 目录下,同样的方法,我们可以在 webpack.config.js 中添加配置
就可以在 index.js 中修改引入方式了
CopyWebpackPlugin 插件和 webpack.ProvidePlugin 插件
CopyWebpackPlugin
可以将 src 下其他的不需要打包的文件直接复制到 dist 目录下webpack.ProvidePlugin
可以在全局引用 lodash 这类的工具库,省去了import在 webpack.config.js 中添加配置
webpack dev server
想象一下,如果我们对代码进行更改,都需要
npm run dev
,会不会远远降低我们的开发效率如果使用
webpack dev server
配置,浏览器会自动启动你的应用程序每次更改文件时,它都会自动刷新浏览器的窗口,比如 vue-cli 中,我们启动监听
npm run dev
时,可以监控我们 src 下文件的改动,那是怎么做到的呢?在 webpack 里其实创建了一个 node 进程,通过 webpack-dev-server 其内部封装了一个 node 的 express 模块
首先安装包
接下来打开 package.json 并调整 scripts
然后在 webpack.config.js 中添加配置
启动监听
npm run dev
,就可以看到webpack dev server
在浏览器中启动了应用项目完整代码链接
webpack-4-cli
学习资料
手写一个webpack4.0配置 从零配置到生产发布(2018) 使用 Webpack 4 和 Babel 7 从头开始创建 React 应用程序 babel 7.x 和 webpack 4.x 配置 vue 项目 阮一峰 Webpack 教程