2009 年, node.js
的诞生, 实现了前端语言向后端的转变。此处省略 1000 字,具体内容请参考 node.js
简史。
通常前端代码都是在浏览器上运行的,但每家浏览器支持力度不同,有些支持新的 JS 语法,有些支持老的 JS 语法。为了实现, 相同一套代码能够到处运行的效果,就出现了前端工具链。工具链的目的就是将代码转译成各个浏览器都支持的脚本。
就前端浏览期打包工具中, webpack
算较为流行的一个。
快速开始
话不多说,现在就快速开始一个 webpack
打包项目。
yarn 安装
首先,全局安装 yarn
命令, 虽然项目依赖包可以直接通过 npm install
进行安装。但是,yarn
在安装性能上要优于 npm
原始安装命令。
$: npm install yarn --global
常用yarn
安装选项 --dev
或 -D
,用于安装开发依赖。
注意 同一个项目中,不要混用
yarn
和npm
。
即选择了一种,就不要再项目中混用另外一种安装命令。减少项目依赖发生不一致。
项目初始化
$: mkdir demo
$: cd demo
$: yarn init -y
快速打包
$: yarn add -D webpack webpack-cli
现在开始实现一个简单的 Hello World
测试。创建一个源码文件 src/index.js
.
console.log("hello webpack!");
现在项目的目录结构如下:
$: tree . -L 2
.
├── node_modules
...
├── package.json
├── yarn.lock
└── src
└── index.js
打开项目文件 package.json
, 在 scripts
中加入打包命令:
{
...
"scripts": {
"build": "webpack"
},
...
}
执行命令:yarn build
, 项目就按默认方式执行了打包。但是,打包过程日志中又这样的警告信息:
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
webpack 提示我们需要设置打包模式。设置打包模式可以通过配置文件,也可以通过命令行选项进行设置。这里,我们快速通过命令行选项进行设置。 修改package.json
文件,将执行脚本进行如下修改:
{
...
"scripts": {
"prd": "webpack --mode=production",
"dev": "webpack --mode=development"
},
...
}
执行, yarn prd
或 yarn dev
,警告信息不再出现。
对比两种模式下的打包结果,可以发现,在production
模式下,打包的结果文件更加的小,而在development
模式下,文件中会添加很多注释信息。关于如何优化最终的发布文件,本文暂不讨论。
打包配置
了解了快速打包过程,现在我们开始进行打包的个性化配置。
默认情况下,webpack
会查找项目目录下的 webpack.config.js
文件作为其配置。也可以通过命令行选项进行具体配置文件的指定。
这里,我们使用默认的方式。在项目根目录下创建webpack.config.js
文件。添加两个基础配置:
- 输入配置
- 输出配置
如下:
const path = require("path");
module.exports = {
entry: {
main: path.resolve(__dirname, "./src/index.js"),
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "main.js",
},
};
在 entry
的定义中,可以仅定义一个入口文件,如 main
键值对应的 src/index.js
源文件。也可以定义多个入口文件, 如:
const path = require("path");
module.exports = {
entry: {
home: path.resolve(__dirname, "./src/index.js"),
post: path.resolve(__dirname, "./src/post.js"),
about: path.resolve(__dirname, "./src/about.js"),
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "[name].js",
},
};
此时,在输出文件的文件名设置上,就不可以使用固定的文件名。而需要使用类似通配符的[name]
的方式,这样在输出文件时,文件名将按照键值生成。结果就是: home.js
,post.js
,about.js
.
执行yarn prd
或yarn dev
命令测试效果。
React 项目实践
真正让webpack
强大的是其丰富的插件功能。这里我们通过手动配置一个 React 项目作为插件配置的学习目标。
babel 插件
真正让 webpack 变强大的是打包插件的引入。最常用也最关键的打包插件就是 babel
插件,让最新的 JS 版本,通过该插件转码后,能够运行在各类浏览器上。
插件安装:
yarn add -D babel-loader @babel/core @babel/preset-env @babel/plugin-proposal-class-properties
如果项目使用 typescript
开发,需要安装 typescript-loader
插件。
因为项目使用 react
开发,还需要安装 @babel/preset-react
插件。
yarn add -D @babel/preset-react
其中插件 babel-loader
还需要进行想要的配置。在项目根目录下,创建.babelrc
文件。进行想要的设置如下:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react" //如果项目使用 react 开发
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
安装完以上插件以后,我们不妨写一个简单的 react
项目测试。
react 项目实践
为了在项目开发过程中使用 react
, 我们还必须对 react
组件库进行安装。
$: yarn add react react-dom
打开 src/index.js
, 写一个最简单的 React 测试:
import React from "react";
import ReactDOM from "react-dom";
const name = "Josh Perez";
const element = <h1>Hello, {name}</h1>;
ReactDOM.render(element, document.getElementById("root"));
保存。现在,如果直接yarn prd
打包,将会出现如下异常,因为,webpack 中还没有相应模块配置。
ERROR in ./src/index.js 4:21
Module parse failed: Unexpected token (4:21)
...
添加上 webpack 模块配置:
const path = require("path");
module.exports = {
entry: {
main: path.resolve(__dirname, "./src/index.js"),
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "main.js",
},
module: {
rules: [
//JS加载模块配置
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
],
},
};
重新执行 yarn prd
命令就可以完成脚本打包。
最后,我们写一个 HTML 页面dist/index.html
,测试一下这个打包后的脚本。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="./main.js" defer></script>
</body>
</html>
如果成功,你就完成了一个从零开始配置的 react 项目。
html 插件
为了测试 React 脚本,上面使用的是手动创建的 HTML 页面。其实,webpack 提供了一个简单 html 插件,可以自动创建一个 HTML 页面。我们提供一个见 HTML 模板即可。
首先,安装插件 yarn add -D html-webpack-plugin
。
在源码文件夹,创建一个简单 HTML 模板文件 src/index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
再增加相应的打包插件配置:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: {
main: path.resolve(__dirname, "./src/index.js"),
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "main.js",
},
module: {
rules: [
// JavaScript
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: "webpack 101",
template: path.resolve(__dirname, "./src/index.html"), // template file
filename: "index.html", // output file
}),
],
};
在执行打包命令前,先将 dist/index.html
文件删除。执行打包命令后,发现 dist/index.html
按模板生成了。
清理插件
经过简单的测试,现在 dist
目录里存在各种不同的打包输出文件。为了保证每次打包前,dist
目录都是空的。不妨再安装一个清理插件: clean-webpack-plugin
.
安装命令: yarn add -D clean-webpack-plugin
。
增加插件配置:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: {
main: path.resolve(__dirname, "./src/index.js"),
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "main.js",
},
module: {
rules: [
// JavaScript
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: "webpack 101",
template: path.resolve(__dirname, "./src/index.html"), // template file
filename: "index.html", // output file
}),
new CleanWebpackPlugin(),
],
};
执行打包命令后,发布目录dist
, 现在只有一个main.js
,之前的发布文件都被清理干净了。
开发环境插件
频繁的执行打包命令,在运行页面,查看效果。这样重复的工作令人厌倦,特别的是开发环境。所以,我们还需要一个更加友好的开发环境,免去我们以上的重复工作。这个插件,就是 webpack-dev-server
.
安装插件: yarn add -D webpack-dev-server
.
将默认的 webpack.config.js
模式修改为 development
模式,同时增加 dev-server
配置,并启用 webpack.HotModuleReplacementPlugin
插件,实现开发环境模块的热加载。
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: {
main: path.resolve(__dirname, "./src/index.js"),
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "main.js",
},
module: {
rules: [
// JavaScript
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
],
},
mode: "development",
devServer: {
historyApiFallback: true,
contentBase: path.resolve(__dirname, "./dist"),
open: true,
compress: true,
hot: true,
port: 8088,
},
plugins: [
new HtmlWebpackPlugin({
title: "webpack 101",
template: path.resolve(__dirname, "./src/index.html"), // template file
filename: "index.html", // output file
}),
new CleanWebpackPlugin(),
new webpack.HotModuleReplacementPlugin(),
],
};
最后,再 package.json
包设置中,增加一个新的命令, 启用该开发服务。
{
...
"scripts": {
"start": "webpack serve",
"prd": "webpack --mode=production",
"dev": "webpack --mode=development"
},
...
}
执行命令: yarn start
, 现在我们可以实时修改源码,webpack
会自动帮我们实现开发模式的打包,并热加载模块。
访问开发服务端口: http://localhost:8088
.
应用打包 vs 库打包
迄今位置,整个打包过程都非常顺利。只需要在 HTML 页面中设置要对应的元素 ID,并引入打包脚本,程序就可以很好的工作。这种打包方式属于应用打包。HTML 页面的写法与脚本直接必须严格配套使用,HTML 页面中必须设置脚本中定义的元素 ID。 这种方式很好,但还不够完美。
我希望 HTML 页面与打包脚本直接的耦合度松散一些。可以通过设置参数的方式设置元素 ID。
为了实现参数功能,我们修改src/index.js
源代码,增加一个导出函数 Greet
. 提供两个参数设置:
selector
: 设置具体渲染的 html dom 节点name
: 名称设置
代码如下:
import React from "react";
import ReactDOM from "react-dom";
export function Greet(selector, name) {
const element = <h1>Hello, {name}</h1>;
const dom = document.querySelector(selector);
if (dom) {
ReactDOM.render(element, dom);
} else {
ReactDOM.render(
<h1>{selector} not found</h1>,
document.querySelector("body")
);
}
}
再将打包目标设置为 library
库类型即可.修改 webpack.config.js
配置:
module.exports = {
...
output: {
path: path.resolve(__dirname, "./dist"),
filename: "welcome.js",
library: 'welcome', //设置输出为 library, 同时,命名为 welcome
},
...
};
完成以上配置后,我们修改 HTML 页面中的调用方式:
<body>
<div id="helo"></div>
<script src="./welcome.js"></script>
<script>
welcome.Greet("#helo", "JayL");
</script>
</body>
运行 yarn start
, 查看效果。
小结
通过该简明教程,我们完成了 webpack
的快速打包,从零开始搭建一个 React 项目,并实现了一个简单的库的打包输出。希望本文对大家有所裨益。