从零配置webpack 5 + React脚手架(一)
前提条件
在开始之前,请确保安装了 Node.js 的最新版本。使用 Node.js 最新的长期支持版本(LTS - Long Term Support),是理想的起步。使用旧版本,你可能遇到各种问题,因为它们可能缺少 webpack 功能以及/或者缺少相关 package 包。
建一个空文件夹
让我们在桌面建一个项目文件夹,名为 my-project ,并使用你的编辑器打开它。 打开终端,快捷键(Ctrl + ~)。
执行以下命令:
npm init -y
上面命令会在 my-project 的根目录生成 package.json 文件,该文件定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、描述信息等数据)。npm install 命令也是根据这个配置文件,自动下载所需的模块。
安装 webpack
安装最新版本或特定版本,请运行以下命令之一:
npm install --save-dev webpack
npm install --save-dev webpack@<version>
如果你使用 webpack 4+ 版本,你还需要安装 CLI。
npm install --save-dev webpack-cli
安装完成后,package.josn 中多了一个 devDependencies 的属性,这是因为我们安装依赖包时 --save-dev || -D 的结果,这代表了开发时的依赖。 --save || -S 安装依赖包,这代表了运行时依赖。
至于为什么用 npm 安装依赖有 package-lock.json 这个文件,而 yarn 安装依赖为 yarn.lock 在这里不过多赘述下次再聊。
此时我们项目的文件结构如下: project
my-project
|- node_modules
|- package-lock.json
|- package.json
新建 config 配置文件夹
在根目录下新建一个文件夹名为 config 用于存放配置文件,在此文件夹下创建三个 .js 文件。
- webpack.common.config.js -- 公共配置文件
- webpack.prod.config.js -- 生产环境配置文件
- webpack.dev.config.js -- 开发环境配置文件
在根目录下再新建一个文件夹名为 src ,在其中新建一个.js 文件,名为 app.js 。
project
my-project
+ |- config
+ |- webpack.common.config.js
+ |- webpack.dev.config.js
+ |- webpack.prod.config.js
|- node_modules
+ |- src
+ |- app.js
|- package.json
在 webpack.common.config.js 文件中输入以下代码:
const path = require('path');
module.exports = {
entry: {
app: './src/app.js',
},
output: {
filename: 'js/bundle.js',
path: path.resolve(__dirname, '../dist'),
},
};
entry 属性定义了入口文件路径, output 定义了编译打包之后的文件名以及所在路径。这段代码的意思是告诉 webpack,入口文件是 src 目录下的 app.js 文件。打包输出的文件名字为 bundle.js ,bundle.js 文件存放的路径为 dist/js/bundle.js。
那该如何打包呢?在 package.json 中配置如下属性:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "start": "webpack --config ./config/webpack.common.config.js"
},
运用 --config 修改指定的配置文件,指向./config/webpack.common.config.js
如果我们的文件结构为:
my-project
|- node_modules
|- package.json
|- webpack.config.js
那么 start 需要修改为:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "start": "webpack"
或者
+ "start": "webpack --config webpack.config.js"
},
虽然此时 app.js 中什么代码都没有,但仍然能打包。
现在可以在终端控制台执行以下命令试试:
npm run start
project
my-project
|- config
|- webpack.common.config.js
|- webpack.dev.config.js
|- webpack.prod.config.js
+ |- dist
+ |- js
+ |- bundle.js
|- node_modules
|- src
|- app.js
|- package.json
那么至此,我们已经成功编译打包了一个 js 文件,即入口文件: app.js 。
安装使用 webpack-merge
npm install --save-dev webpack-merge
开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。
虽然,以上我们将生产环境和开发环境做了略微区分,但是,请注意,我们还是会遵循不重复原则(Don't repeat yourself - DRY),保留一个“通用”配置。为了将这些配置合并在一起,我们将使用一个名为 webpack-merge 的工具。通过“通用”配置,我们不必在环境特定(environment-specific)的配置中重复代码。
这就是为什么我一开始在 config 文件夹下创建三个 .js 文件的原因
webpack.prod.config.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.config.js');
module.exports = merge(common, {
mode: 'production',
});
在根目录下新建一个文件夹名为: public ,再新建一个 index.html 文件 project
my-project
|- config
|- webpack.common.config.js
|- webpack.dev.config.js
|- webpack.prod.config.js
|- node_modules
+ |- public
+ |- index.html
|- src
|- app.js
|- package.json
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>my-project(webpack + react)</title>
</head>
<body>
<div id="root"></div>
</body>
<script src="../dist/js/bundle.js"></script>
</html>
回到起初创建的 src/app.js 文件:
let root =document.getElementById('root');
root.innerHTML = 'my-project!!!!!';
package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack --config ./config/webpack.common.config.js",
+ "build": "webpack --config ./config/webpack.prod.config.js"
},
执行以下代码试试:
npm run build
执行后用浏览器打开 public/index.html 文件看看是不是有“my-project!!!!!”。
安装 React
执行以下命令:
npm install --save react react-dom
安装完成之后,我们就可以写 react 的 JSX 语法了。
src/app.js
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>my-project!!!!!</div>
);
}
}
export default App;
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app';
ReactDOM.render(<App />, document.getElementById('root'));
webpack.common.config.js
const path = require('path');
module.exports = {
entry: {
- app: './src/app.js',
+ index: './src/index.js',
},
output: {
filename: 'js/bundle.js',
path: path.resolve(__dirname, '../dist')
}
}
ok,现在再执行 npm run bulid
试试。我们会发现 build 打包失败。接着往下解决失败。
安装Babel
因为 webpack 根本识别不了 jsx 语法,所以需要使用 loader 对文件进行预处理。 其中,babel-loader,就是这样一个预处理插件,它加载 ES2015+ 代码,然后使用 Babel 转译为 ES5。那我们开始配置它吧!
首先安装依赖:
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime
- babel-loader:使用 Babel 和 webpack 来转译 JavaScript 文件。
- @babel/core:babel 的核心模块
- @babel/preset-env:转译 ES2015+的语法
- @babel/preset-react:转译 react 的 JSX
- @babel/plugin-proposal-class-properties:用来编译类(class)
- @babel/plugin-transform-runtime:防止污染全局,代码复用和减少打包体积
webpack.common.config.js
const path = require('path');
module.exports = {
entry: {
index: './src/index.js',
},
output: {
filename: 'js/bundle.js',
path: path.resolve(__dirname, '../dist'),
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-class-properties',
],
},
},
},
],
},
};
好的,至此我们就能用 jsx 语法编写代码了。打包看看,是不是成功了。
安装HtmlWebpackPlugin
npm install --save-dev html-webpack-plugin
webpack.prod.config.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.config.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = merge(common, {
mode: 'production',
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
filename: 'index.html',
inject: 'body',
minify: {
removeComments: true,
},
}),
],
});
- template:基于我们自己定义的 html 文件为模板生成 html 文件
- filename:打包之后的 html 文件名字
- inject:将 js 文件注入到 body 最底部
- minify:压缩 html 文件时的配置
- removeComments:去除注释
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>my-project(webpack + react)</title>
</head>
<body>
<!-- 跟标签 -->
<div id="root"></div>
</body>
</html>
现在执行 npm run build
打包时,dist 文件夹中就多出来 index.html 文件,因此自动编译 html 完成,打开看看效果。
解决浏览器缓存,给打包出的 js 文件换个不确定名字
为什么需要换 js 文件名字呐???防止浏览器缓存机制带来的业务代码不更新问题。 浏览器打开 html 页面后,会去请求对应的 js 文件。当客户端请求 js 文件的时候发现名字是一样的,那么它很有可能不发新的 js 包,直接读取了缓存包;如果更换名字后在缓存区中寻找不到,就会去远端服务器中拉取新的 js 资源从而读取到最新的代码。
怎么换不确定名字呐。安排!!! webpack.prod.config.js
module.exports = merge(common, {
output: {
filename: 'js/[name]-bundle-[hash:6].js',
},
});
- [name] 打包入口名称
- [hash] 哈希串默认长度为 20,:6 为取前六位
执行 npm run build
打包看看 js 文件是不是不一样了。
现在让我们在 src/app.js 文件中随便在写点东西后再次打包,你会发现 dist/js 的文件夹中又多了个.js,之前的 js 文件并没有清理掉。
打包编译前清理 dist 目录
安装 clean-webpack-plugin
npm install --save-dev clean-webpack-plugin
webpack.prod.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = merge(common, {
plugins: [
new CleanWebpackPlugin(),
],
});
现在执行 npm run build
,再检查 dist/js 文件夹。你现在应该不会再看到旧的文件,只有构建后生成的文件!
相信在这肯定有人发现了,每次看效果都非常麻烦。ok 接下来就配置一下webpack-dev-server
自动编译打包
安装 webpack-dev-server
npm install --save-dev webpack-dev-server
webpack.dev.config.js
const path = require('path');
const { merge } = require('webpack-merge');
const common = require('./webpack.common.config.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = merge(common, {
mode: 'development',
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: 9000,
compress: true,
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
inject: 'body',
hash: false,
}),
],
});
- contentBase: 启服务的文件
- port: 端口号
- compress: 为每个静态文件开启gzip压缩:
package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
- "start": "webpack --config ./config/webpack.common.config.js",
+ "start": "webpack serve --open --config ./config/webpack.dev.config.js",
"build": "webpack --config ./config/webpack.prod.config.js"
},
如果不出意外的话执行npm run start
就能正常启动本地端口 9000 并且自动在默认浏览器中打开页面。
当你在 app.js 中随意加点文案,回到浏览器中打开的页面都会自动更新了,至此自动编译打包完成。
转载自:https://juejin.cn/post/6943164629434499109