Webpack 4 + React Part 1
从零配置webpack 4+react脚手架(一)
前言:
如果你和我一样学习了webpack相关的教程,并跟着webpack官方指南进行了一些简单的配置,但是不知道如何去使用它,那么这个系列的文章将通过搭建webpack+react脚手架给予你一定的配置经验,写这个系列的文章一是为了方便以后自己有配置需求时可以及时回顾,二是加强自己对于webpack的理解。我会尽可能详细地一步一步讲解这个脚手架配置步骤,也会对一些需要注意的点进行提醒,希望能帮助到大家~
前提:
- 务必安装Node.js的最新版本,在控制台中输入
node -v
查看当前版本,若没有安装或不是最新版本,这里提供Node.js官网以便下载 - 已经了解过webpck的相关配置,不然你跟着这篇文章操作并不能增加多少熟练度,当然了,你可以先关注一下,之后再来看,题外话,如果你是webpack老手了,请务必关闭这篇文章,你的时间非常值钱。
- 当前文章的写作基于mac os环境下完成,若是windows,与我相同操作却得不到结果的,请Google
- 保持耐心,我会将这篇文章分为许多小节,防止太多时间专注造成的疲劳,你可以休息一会儿看一节。
开始吧!
建一个空文件夹
让我们在桌面建一个空文件夹,名为 webpck-react-scaffold
,并使用你的编辑器打开它。
将此文件夹拖到终端,执行:
npm init -y
上面命令会在你的根目录生成 package.json
文件,该文件定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。npm install
命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。
安装webpack
因为我们使用的是 webpack 4+
版本,还需要安装 webpack-cli
,执行以下命令:
npm install --save-dev webpack webpack-cli
安装完成,你会发现在 package.josn
中多了一个 devDependencies
属性,这是因为我们安装依赖包时 --save-dev
的结果,这代表了开发时的依赖。之后我们会只用 --save
安装依赖包,这代表了运行时依赖。
我们确认一下,现在根目录下的文件结构如下:
webpack-react-scaffold
|- node_modules
|- package.json
接下来,我们在根目录下新建一个文件夹名为 config
用于存放配置文件,在此文件夹下创建一个 .js
文件名为 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')
}
}
webpack 配置是标准的 Node.js的CommonJS 模块,它通过require来引入其他模块,通过module.exports导出模块,由 webpack 根据对象定义的属性进行解析。
entry
属性定义了入口文件路径, output
定义了编译打包之后的文件名以及所在路径。
这段代码的意思是告诉webpack,入口文件是 src
目录下的 app.js
文件。打包输出的文件名字为 bundle.js
,保存在上一级目录下的 dist
文件夹中。
我们创建一个文件夹名为 src
,在其中新建一个js文件名为 app.js
,现在我们的目录结构如下:
webpack-react-scaffold
+ |- config
+ |- webpack.common.config.js
|- node_modules
+ |- src
+ |- app.js
|- package.json
那我们怎么打包呢?在 package.json
中配置如下属性:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "start": "webpack --config ./config/webpack.common.config.js"
},
好了,我们试试怎么打包吧,虽然你的 app.js
中什么代码也没有。
在控制台中输入以下代码:
npm run start
想必你也看出来了,为什么是 “start”,--config
选项来指定配置文件。
执行之后,你会发现根目录多出了一个文件夹: dist/js
,其中有一个js文件: bundle.js
,那么至此,我们已经成功编译打包了一个js文件,即入口文件: app.js
。
使用webpack-merge
我们将使用一个名为 webpack-merge 的工具。通过“通用”配置,我们不必在环境特定(environment-specific)的配置中重复代码。简单来说就是生产环境不同,我们要给的配置也有所不同,但是可以共用一个共有的配置。
我们先从安装 webpack-merge 开始:
npm install --save-dev webpack-merge
安装结束之后,我们在 config
这个文件夹下新建两个文件,分别为 webpack.prod.config.js
和 webpack.dev.config.js
,这两个文件分别对应生产和开发两个环境的配置。
现在的目录结构:
webpack-react-scaffold
|- config
|- webpack.common.config.js
+ |- webpack.prod.config.js
+ |- webpack.dev.config.js
|- node_modules
|- src
|- app.js
|- package.json
在 webpack.prod.config.js
中输入以下代码:
const merge = require('webpack-merge');
const common = require('./webpack.common.config.js');
module.exports = merge(common, {
mode: 'production',
});
回到我们之前创建的 app.js
文件,输入代码:
var root =document.getElementById('root');
root.innerHTML = 'hello, webpack!';
在根目录下创建一个文件夹名为: public
,再新建一个html文件,名为: index.html
,以下内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>从零配置webpack4+react脚手架</title>
</head>
<body>
<div id="root"></div>
<script src="../dist/js/bundle.js"></script>
</body>
</html>
现在的目录结构是这样子(只要不编译打包,要引入的 bundle.js
就没有):
webpack-react-scaffold
|- config
|- webpack.common.config.js
|- webpack.prod.config.js
|- webpack.dev.config.js
|- node_modules
+ |- public
+ |- index.html
|- src
|- app.js
|- package.json
打包之前,我们修改 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
我们可以看到,webpack重新进行了编译,这和执行
webpack --config config/webpack.prod.conf.js
是一样的效果。
现在你可以打开用浏览器 public/index.html
,看看是不是有东西了~~
安装React
在控制台输入以下代码:
npm install --save react react-dom
安装完成之后,我们就可以写react的JSX语法了。
这里为了和react官方脚手架 create-react-app
的目录结构相类似,我们在 src
文件夹下新建一个js文件, index.js
,用于渲染根组件。
在 index.js
输入以下代码:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
并用jsx语法重写 app.js
:
import React from 'react';
function App() {
return (
<div className="App">Hello World</div>
);
}
export default App;
对 webpack.common.config.js
文件中的入口进行修改,因为我们现在要编译打包的应该 index.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')
}
}
现在尝试一下重新运行 npm run build
,会发现打包失败了,为什么呢?接着看.....
使用babel 7
为什么我们上面写jsx会打包不了呢,因为webpack根本识别不了jsx语法,那怎么办?使用loader对文件进行预处理。 其中,babel-loader,就是这样一个预处理插件,它加载 ES2015+ 代码,然后使用 Babel 转译为 ES5。那开始配置它吧!
首先安装babel相关的模块:
npm install --save-dev babel-loader @babel/preset-react @babel/preset-env @babel/core
- babel-loader:使用Babel和webpack来转译JavaScript文件。
- @babel/preset-react:转译react的JSX
- @babel/preset-env:转译ES2015+的语法
- @babel/core:babel的核心模块
理论上我们可以直接在 webpack.common.config.js
中配置"options",但最好在当前根目录,注意,一定要是根目录!!! 新建一个配置文件 .babelrc
配置相关的"presets":
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
// 大于相关浏览器版本无需用到 preset-env
"edge": 17,
"firefox": 60,
"chrome": 67,
"safari": 11.1
},
// 根据代码逻辑中用到的 ES6+语法进行方法的导入,而不是全部导入
"useBuiltIns": "usage"
}
],
"@babel/preset-react"
]
}
这里有关bebel的配置可上官网查询文档。
再修改 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)$/,
use: 'babel-loader',
exclude: /node_modules/,
}
]
}
}
test
规定了作用于以规则中匹配到的后缀结尾的文件, use
即是使用 babel-loader
必须的属性, exclude
告诉我们不需要去转译"node_modules"这里面的文件。
接下来:
npm run build
是不是能打包成功了呢?回到你的html页面,看一下是否打印出了“hello webpack”吧!
我们再最后确认一下我们的目录:
webpack-react-scaffold
|- config
|- webpack.common.config.js
|- webpack.prod.config.js
|- webpack.dev.config.js
|- node_modules
|- public
|- index.html
|- src
+ |- index.js
|- app.js
+ |- .babelrc
|- package.json
这一小节就到这里,你会发现有很多功能还是没有得以实现,比如自动生成html文件,实时刷新页面等,下一节开始我们会逐步优化我们的配置!
>> 本博客分享自vortesnail/blog,供自学使用,非商用 <<