Webpack 4 发布了!这个流行的模块打包工具获得了大量更新。
Webpack 4,有什么最新的特性?大规模的性能改进,零配置和合理的默认设置。
这是一篇新鲜出炉的 webpack 4 教程文章。
零配置的模块打包工具 webpack 4
webpack 非常强大且拥有许多独特的特性,其中有一个难点,就是它的配置文件。
为中大型项目提供 webpack 配置理所当然,缺少了它你将无法运行项目。但是,对于小项目而言,webpack 的配置有点烦人,特别是当你只想要运行一些小的示例应用程序时。
所以这也是为什么 Parcel 能够获得如此多关注的原因。
这里着重提一点:webpack 4 默认不需要配置文件!
让我们开始试试看吧。
webpack 4:从零配置开始
本地创建一个目录
mkdir webpack-4-quickstart && cd $_
初始化 package.json
文件
npm init -y
接着安装 webpack 4 和 webpack-cli
npm i webpack --save-devnpm i webpack-cli --save-dev
打开 package.json文件,添加下面的启动脚本,添加完成后记得保存
"scripts": { "build": "webpack"}
接下来尝试运行下面的命令:
npm run build
我们看看发生了什么:
ERROR in Entry module not found: Error: Can't resolve './src' in '~/webpack-4-quickstart'
上面这个 Error 说的是,webpack 4 在 ./src目录中找不到入口起点。如果你不明白这些错误的含义,可以查看我先前的文章switching from Gulp to webpack
简单来说:入口起点就是 webpack 用来构建你 Javascript 包的一个起始文件。
在以前的 webpack 版本中,必须要在 webpack.config.js 配置文件中定义入口起点。
从 webpack 4 开始,不再需要定义这个入口起点,它会自动以 ./src/index.js 作为入口起点。
要体验这些新功能很简单,接下来让我们创建 ./src/index.js
文件并写入下面的内容:
console.log(I'm a silly entry point
);
然后再一次运行打包命令:
npm run build
你会在项目中看到一个打包后文件 ~/webpack-4-quickstart/dist/main.js
。
额,等等,你一定会问,不需要再同时指定输出文件(output file)了吗?是的,连这个也不需要了。
在 webpack 4 中,既不需要定义入口文件也不需要定义输出文件。
webpack 的主要优势在于代码分割。但请相信我,零配置工具可以加快你的速度。
综上所述,webpack 4 不需要配置文件。
它会默认以你项目中的 ./src/index.js 文件为入口文件,此外,它会在 ./dist/ 中输出打包后的文件。
在下一节中,我们将看到 webpack 4 的另一个不错的功能:生产和开发模式。
生产和开发模式
拥有 2 个配置文件是 webpack 开发中的常见模式。
一个典型的项目可能有:
- 一个开发环境的配置文件,用来定义 webpack 开发服务器和一些其他设置项
- 一个生产环境的配置文件,用来定义 UglifyJSPlugin,sourcemaps 等等这些
虽然较大的项目可能仍然需要以上 2 个文件,但在 webpack 4 中,你可以在没有一行配置的情况下完成上面的需求。
那么,如何来做呢?
webpack 4 提到了生产和开发模式。
事实上,如果你在前面运行 npm run build
命令时,稍加注意就会留意到在终端里有这样一段输出:
The ‘mode’ option has not been set. Set ‘mode’ option to ‘development’ or ‘production’ to enable defaults for this environment.
上面这句话是什么意思呢?让我们接着看。
打开 package.json 文件,添加如下配置:
"scripts": { "dev": "webpack --mode development", "build": "webpack --mode production"}
然后运行:
npm run dev
并看看./dist/main.js 文件。你看到了什么?是的,我知道,和之前一样大的一个无聊的打包文件。
那么你再试着运行这个命令:
npm run build
并看看./dist/main.js。现在你看到了什么?一个更小的打包文件!
是的,生产模式可以开箱即用地进行各种优化。例如 压缩, 作用域提升等等。
而开发模式只是针对速度进行了优化,仅提供了一种不压缩的打包文件。
覆盖默认的入口/输出
我喜欢 webpack 4 的零配置,但是如何覆盖默认入口和输出呢?只需要在 package.json
文件中定义即可。
示例如下:
"scripts": { "dev": "webpack --mode development ./foo/src/js/index.js --output ./foo/main.js", "build": "webpack --mode production ./foo/src/js/index.js --output ./foo/main.js"}
使用 Babel 7 转换 ES6
现代 Javascript 主要是用 ES6 编写的。
但并不是每个浏览器都知道如何处理 ES6,我们需要某种转换。转换的行为是为了让旧的浏览器能够理解处理 ES6 代码。
webpack 不知道如何进行转换但是它有 loaders:你可以将它们视为转换器。
babel-loader 是用于将 ES6 及以上版本转换成 ES5 的 webpack loader。
为了使用这些转换器(loader),我们需要先安装它们。
-
babel core
-
babel loader
-
babel preset env
npm i @babel/core babel-loader @babel/preset-env --save-dev
接下来,通过在项目文件夹中创建名为 .babelrc 的新文件来配置 Babel:
{ "presets": [ "@babel/preset-env" ]}
此时我们有 2 个地方都可以配置 babel-loader:
- 使用 webpack 的配置文件
- 在 npm scripts 中添加
--module-bind
是的,我知道你在想什么。webpack 4 标榜自己为零配置打包工具。为什么还要再次配置这些配置文件?
webpack 4 中零配置的概念适用于:
- 入口起点
- 输出
- 生产和开发模式
这就足够了。但是对于在 webpack 4 中使用加载器,你仍然需要创建配置文件。
我问过 Sean 这件事。webpack 4 中的加载器是否与 webpack 3 相同?有没有计划为像 babel-loader 这样的普通 loader 提供 0 配置?
这是他给我的回复:
“For the future (after v4, maybe 4.x or 5.0), we have already started the exploration of how a preset or addon system will help define this. What we don’t want: To try and shove a bunch of things into core as defaults What we do want: Allow other to extend”
现在你仍然需要依赖 webpack.config.js。让我们接下来来看看…
搭配配置文件使用 babel-loader
创建一个名为 webpack.config.js 的新文件并配置加载器:
module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] }};
这里无需指定入口点,除非是你要自定义入口点。
接着打开 ./src/index.js 文件,写入一些 ES6 代码:
const arr = [1, 2, 3];const iAmJavascriptES6 = () => console.log(...arr);window.iAmJavascriptES6 = iAmJavascriptES6;
运行打包命令:
npm run build
现在我们可以看一下 ./dist/main.js 文件,查看转换后的代码。
无需配置文件使用 babel-loader
还有另一种方法可以使用 webpack loaders。
--module-bind 标志允许你从命令行指定 loaders。这个标志不仅版本 4 有,版本 3 就已存在。
要在没有配置文件的情况下使用 babel-loader,请在 package.json 中配置你的 npm 脚本,如下所示:
"scripts": { "dev": "webpack --mode development --module-bind js=babel-loader", "build": "webpack --mode production --module-bind js=babel-loader" }
在 React 中使用 webpack 4
安装 React:
npm i react react-dom --save-dev
接着添加babel-preset-react
:
npm i @babel/preset-react --save-dev
在 .babelrc 中配置 preset:
{ "presets": ["@babel/preset-env", "@babel/preset-react"]}
打开 webpack.config.js
文件,配置 loader,如下所示:
module.exports = { module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] }};
如需要测试,你可以在 ./src/App.js 中创建一个 React 组件:
import React from "react";import ReactDOM from "react-dom";const App = () => { return ( <div> <p>React here!</p> </div> );};export default App;ReactDOM.render(<App />, document.getElementById("app"));
然后在 ./src/index.js
中引入该组件:
import App from "./App";
再次运行打包命令。
HTML 插件
webpack 中处理 HTML 的插件是:html-webpack-plugin、html-loader,运行下面的命令安装这 2 个插件:
npm i html-webpack-plugin html-loader --save-dev
接着,更新 webpack 的配置文件webpack.config.js
:
const HtmlWebPackPlugin = require("html-webpack-plugin");module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } }, { test: /\.html$/, use: [ { loader: "html-loader", options: { minimize: true } } ] } ] }, plugins: [ new HtmlWebPackPlugin({ template: "./src/index.html", filename: "./index.html" }) ]};
然后,在src
目录下创建入口 html 文件:../src/index.hmtl
<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8"> <title>webpack 4 quickstart</title></head><body> <div id="app"> </div></body></html></
运行打包命令后,我们可以查看./dist
目录,应该可以看到生成的 index.html 文件。在浏览器中打开./dist/index.html
,你也应该可以看到 React 组件正常显示了。
在 Vue 中使用 webpack 4
我真的很喜欢 Vue,因为它是许多项目的开发首选。
如果要在 webpack 项目中使用 Vue,可以使用以下命令安装库:
npm i vue --save-dev
接着用下面的 vue 实例替换 src/index.js
中的内容:
import Vue from "vue";const app = new Vue({ el: "#app", data: { message: "Hello Vue!" }});
接下来配置 webpack.config.js 以加载 Vue 包:
resolve: { alias: { vue$: "vue/dist/vue.esm.js" }}
现在,你可以运行构建命令,并将你的 Vue 实例注入到 HTML 文件中。
提取 CSS 到一个单独的文件中
webpack 自身是不知道如何将 CSS 提取打包到文件中的。
webpack 4.0 以前,可以通过 extract-text-webpack-plugin 插件,把 CSS 样式从 JS 文件中提取到单独的 CSS 文件中。但不幸的是,这个插件与 webpack 4 不太匹配。
Michael Ciniawsky 给的说法是这样的:
extract-text-webpack-plugin reached a point where maintaining it become too much of a burden and it’s not the first time upgrading a major webpack version was complicated and cumbersome due to issues with it
webpack 4.0 以后,mini-css-extract-plugin 这个插件可以解决上面的问题。
提示: 确保 webpack 版本升级至 4.2.0。否则 mini-css-extract-plugin 插件无法正常工作
运行命令安装所需插件:
npm i mini-css-extract-plugin css-loader --save-dev
接着创建一个 CSS 文件 main.css
用来测试打包后的效果。
/* *//* CREATE THIS FILE IN ./src/main.css *//* */body { line-height: 2;}
配置 webpack.config.js
文件的 plugin 和 loader:
const HtmlWebPackPlugin = require("html-webpack-plugin");const MiniCssExtractPlugin = require("mini-css-extract-plugin");module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } }, { test: /\.html$/, use: [ { loader: "html-loader", options: { minimize: true } } ] }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"] } ] }, plugins: [ new HtmlWebPackPlugin({ template: "./src/index.html", filename: "./index.html" }), new MiniCssExtractPlugin({ filename: "[name].css", chunkFilename: "[id].css" }) ]};
再在我们前面创建的入口文件 ./src/index.js
中导入 CSS 文件 main.css
:
//// PATH OF THIS FILE: ./src/index.js//import style from "./main.css";
运行打包命令:
npm run build
打包完成后,我们在 ./dist 目录下应该可以看到提取出的 CSS 文件。
webpack 开发服务器
每次你修改了项目代码,都要运行 npm run dev
才能在浏览器中看到修改后的效果?不,这不是我们所要的。
使用 webpack 配置开发服务器只需一分钟,一旦配置好 webpack 开发服务器,它将在浏览器中启动你的应用程序,每次更改文件时,它都会自动刷新浏览器的窗口。
运行下面命令安装所需的包:
npm i webpack-dev-server --save-dev
打开 package.json
文件,配置下面的脚本命令:
"scripts": { "start": "webpack-dev-server --mode development --open", "build": "webpack --mode production"}
现在,运行 start 命令:
npm run start
你可以看到 webpack 开发服务器在浏览器中启动了你的应用。