[关闭]
@gyyin 2020-03-29T23:47:41.000000Z 字数 5719 阅读 278

环境搭建:webpack 和 Parcel

慕课专栏


1. 前言

从这篇开始,将会带大家一起来学习 React 的相关知识。React 是当前最火的前端框架之一,但它本身的语法不可以直接在浏览器端运行,所以在正式开始学习 React 之前,我想带领大家先学习一下如何搭建 React 环境。

2. 打包工具

随着前端的迅速发展,ECMAScript 语法也变得越来越完善,NodeJS 诞生后各种自动化的工具像雨后春笋一样冒出来。
前端的需求也越来越多,比如我们要将 ES6、JSX 等语法转成浏览器可以识别的,于是 Babel 诞生了。我们需要对代码进行压缩、编译、单元测试等等,之前流行的是 Grunt,后来是 Gulp,现在则是 webpack,前端工具处于不断发展完善之中。
今天,我们将会用 webpack 和 Parcel 来搭建 React 环境。

本文不会对两者语法和用处进行详细地讲解,有需要的同学可以自行查阅资料。

3. webpack

webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。
webpack 会分析项目结构,找到 JavaScript 模块以及一些不能直接运行的语言(Sass、TypeScript等),将其转换供浏览器使用。

3.1 安装

在安装 webpack 之前,需要先安装 NodeJS 和 npm 环境,这里不作讲解,可以参考廖雪峰的这篇文章:安装Node.js和npm
首先,我们先创建一个项目,安装 webpack 依赖。

  1. mkdir webpack-react
  2. cd webpack-react
  3. npm init // 初始化
  4. npm i webpack webpack-cli -D // 安装相关包

npm i 就是 npm install,-D 就是 -dev.

我们先来写个简单的 hello, world,在 package.jsonscripts 里面配置一下。在 webpack4 里面,允许我们不写 webpack.config.js

  1. // index.js
  2. console.log("hello, world")

当然,只是简单地使用,这样就够了,更多情况下我们还是要手写配置文件。

3.2 loader 和 plugin

在 webpack 中,有 loader 和 plugin 两个概念。
loader 是一个转换器,它描述了怎么处理模块,比如将 TypeScript 转换为 JavaScript,将内联的图像转换为 data url 等等。
而 plugin 则是解决一些 loader 无法实现的其他事,比如代码压缩、去除 console.log等等,可以用来处理各种各样的任务。

3.3 配置文件

我们来创建一个 webpack 配置文件,在根目录下新建一个 webpack.config.js 文件。

  1. const path = require('path');
  2. module.exports = {
  3. mode: 'development', // 开发模式
  4. entry: path.resolve(__dirname,'./src/index.js'), // 入口文件
  5. output: {
  6. filename: 'build.js', // 打包后的文件名称
  7. path: path.resolve(__dirname,'./dist') // 打包后的目录
  8. }
  9. }

然后修改 package.json 里面的 build 命令,设置为从配置文件读取。

  1. "build": "webpack --config webpack.config.js"

3.4 配置模板

我们在打包 webpack 文件的时候,经常会给文件名加哈希后缀,这是为什么呢?
因为浏览器会对上一次的文件做缓存,如果文件名一样的话就会被缓存,然而我们希望打包之后发到线上的文件不要使用缓存,所以就要加上哈希值,保证每次生成的文件名不一样。

image_1e4jff5h41fva1q6l1h5vikd4p51q.png-349.8kB

也是这个原因,如果我们每次都要在 HTML 文件里面手动引入打包后的 JS 文件,这该多么麻烦。因此,有个叫 html-webpack-plugin 的插件帮我们完美解决这个问题。
我们在 public 文件夹下新建一个 index.html 文件,然后修改 webpack 配置,引入 html-webpack-plugin 插件。

  1. const path = require('path');
  2. const HtmlWebpackPlugin = require('html-webpack-plugin')
  3. module.exports = {
  4. mode:'development',
  5. entry: path.resolve(__dirname,'./src/index.js'), // 入口文件
  6. output: {
  7. filename: '[name].[hash:8].js', // 打包后的文件名称
  8. path: path.resolve(__dirname,'./dist') // 打包后的目录
  9. },
  10. plugins:[
  11. new HtmlWebpackPlugin({
  12. template:path.resolve(__dirname,'./public/index.html')
  13. })
  14. ]
  15. }

3.5 清理上一次打包文件

我们已经可以看到生成的文件后面带上了哈希,index.html 也自动引入了这个 JS 文件,但发现每次 build 之后,上次打包的文件还在 dist 文件夹下面。
这样很明显不符合我们的需求,赶紧去找了找。刚好找到一个 clean-webpack-plugin 插件,可以完美解决我们的需求。

  1. const { CleanWebpackPlugin } = require('clean-webpack-plugin')
  2. module.exports = {
  3. plugins:[new CleanWebpackPlugin()] // 引入 CleanWebpackPlugin 插件
  4. }

再执行一次 npm run build,可以看到前几次生成的文件被清除了。

3.6 css

我们已经可以成功打包 JS 文件,但如果想对 css 文件做解析该怎么办?这里涉及到两个 loader 和一个插件。
css-loader 是将引入的 css 文件打包到 JS 文件里面。
style-loader 是将打包到 JS 文件中的 css 代码解析到 HTML 的 style 标签里面。
mini-css-extract-plugin 是将 css 文件单独打包成 css 文件的一个插件。
我们直接在配置里面增加这些:

  1. module: {
  2. rules: [
  3. {
  4. test:/\.css$/,
  5. use:['style-loader','css-loader'] // 从右往左解析
  6. }
  7. ]
  8. },
  9. plugins: [
  10. new MiniCssExtractPlugin({
  11. filename: "[name].[hash].css",
  12. chunkFilename: "[id].css",
  13. })
  14. ]

3.7 Babel

在我们写代码中,经常会用到一些浏览器暂时还不支持的新 ES 语法,为了支持这些新语法,我们需要来配置 Babel。
我们可以添加 babel-loader@babel/preset-env 来支持 ES6/ES7/ES8 等语法。

  1. npm i babel-loader @babel/preset-env @babel/core -D

我们在根目录下创建 .babelrc 文件来编写 babel 的相关配置。

  1. // .babelrc
  2. {
  3. "presets": ["@babel/env"]
  4. }

但是这个只会将我们的 ES6 代码转成 ES5 代码,如果是 ES5 中本来就不支持的 API,比如 Promise、Map 等等,那就没办法转了。
所以是时候使用 polyfill 了,可以使用 babel-plugin-transform-runtime 这个插件来 polyfill 一些新的 API。
安装插件:

  1. npm i @babel/plugin-transform-runtime @babel/runtime -D

修改 .babelrc 配置文件:

  1. {
  2. "plugins": [
  3. "@babel/plugin-transform-runtime"
  4. ],
  5. "presets": ["@babel/env"]
  6. }

3.8 React

终于说到了本文的重点了,前面的铺垫工作都已经完成了,那么我们该如何配置 React 的环境呢?
这里依然需要一个 babel 的插件来支持,安装 @babel/preset-react 就可以转换 JSX 语法。
.babelrc 配置文件:

  1. {
  2. "plugins": [
  3. "@babel/plugin-transform-runtime"
  4. ],
  5. "presets": ["@babel/env", "@babel/preset-react"]
  6. }

我们将入口的 index.js 换成 index.jsx,写两行 React 代码试试。

  1. import React from 'react';
  2. import ReactDOM from 'react-dom'
  3. function App() {
  4. return (
  5. <div>hello, world</div>
  6. )
  7. }
  8. ReactDOM.render(
  9. <App />,
  10. document.getElementById("app")
  11. )

执行一下 npm run build,很完美。

3.9 webpack-dev-server 热更新

我们现在每次 build 生成文件,然后手动在本地运行 HTML 文件。如果之后用到 react-router,本地打开 HTML 文件就只能用 HashRouter 了,而且我希望能本地启一个服务器,支持热更新。
首先,我们来安装 webpack-dev-server,它会在本地启动一个服务,将你的文件放到内存里面,也会响应你的修改来做热更新。

  1. npm i webpack-dev-server -D

接着,我们来修改 webpack 的配置,增加热更新配置,这里设置监听 3000 端口。

  1. const webpack = require('webpack')
  2. // webpack.config.js
  3. devServer: {
  4. port: 3000,
  5. hot: true,
  6. contentBase: './dist'
  7. },
  8. plugins: [
  9. new Webpack.HotModuleReplacementPlugin()
  10. ]

然后,我们再来修改 package.json 文件,增加 dev 的 script。

  1. "dev": "webpack-dev-server --config webpack.config.js --open"

我们运行一下 npm run dev,发现会自动打开一个窗口,我们的页面已经跑在了 localhost:3000 上面。
至此,一个完整的 React 环境配置就已经搞定了,我把它放到了 GitHub 上面:webpack-react

3.10 create-react-app

当然,如果你不想手动操作那么繁琐的配置,你也可以试试 create-react-app,这是生成 React 项目配置的一个脚手架。
快速开始:

  1. npx create-react-app my-app
  2. cd my-app
  3. npm start

当你准备部署到生产环境的时候,你可以执行 npm run build
如果你想自定义 webpack 的配置,那么可以使用 ejecting 来暴露出 webpack 的配置。

  1. npm run eject

如果你想使用 css-modulesTypeScript 等等,可以去看官方的详细文档:Create React App 官方文档

4. Parcel

由于 Webpack 的繁琐配置,很多开发者都希望有一个配置更简单的打包工具出来,Parcel 就因此诞生了。它利用多核处理提供了极快的速度,并且不需要任何配置。

4.1 安装

首先我们来创建一个新的项目:

  1. mkdir parcel-react
  2. cd parcel-react
  3. npm init

然后我们通过 Yarn 或者 npm 来安装 Parcel:

  1. // yarn
  2. yarn global add parcel-bundler
  3. // npm
  4. npm install -g parcel-bundler

当然你也可以安装到项目里面:

  1. npm install parcel-bundler -D

-D 相当于 -dev,-S 相当于 --save

Parcel 一般需要一个入口文件,一般是 HTML 或者 JavaScript 文件,我们这里以 HTML 文件为入口。
接下来安装 React 相关依赖包:

  1. npm install -S react
  2. npm install -S react-dom
  3. npm install -D parcel-bundler

此时 Parcel 相关的依赖已经安装好了。可能你会好奇为什么没有安装 Babel 相关的包呢?这样可以支持 ES6 以及 JSX 的语法吗?

Parcel 里面已经默认安装了 @babel/core@babel/preset-env@babel/plugin-transform-react-jsx 等包,我们不需要再额外安装。

4.2 入口文件

接下来,我们需要创建一个入口的 HTML 文件,然后在 package.jsonscripts 里面添加这么一句。

  1. // package.json
  2. "scripts": {
  3. "start": "parcel index.html"
  4. }

然后需要在你的 HTML 文件里面引入你的 .jsx 入口文件,Parcel 会从这个入口文件开始解析。

code.png-126.2kB

这样我们就可以用 npm start 的形式来启动项目了。启动项目的时候,Parcel 会默认监听 1234 这个端口号,启动一个类似 webpack-dev-server 的服务。

image_1e4iptk1610bjn485gd88bemb11.png-34.1kB

添加 --open 的参数,会在服务启动后自动帮你打开对应的地址。

  1. parcel index.html --open

如果你想换其他端口,可以在 scripts 里面修改。

  1. parcel index.html --port 3000

当然,Parcel 的配置也许不能满足你的要求,比如我想使用装饰器该怎么办?我想使用类属性怎么办?

Parcel 也允许你手动添加一个 .babelrc 文件,在这个文件里面写上你的配置。

code.png-54.1kB

这样一个简单的基于 Parcel 的 React 环境就搭建好了。为了方便大家参考,我这里把配置了 React/Redux 和 React/Mobx 的项目放到了 GitHub。

Parcel-React 项目地址:Parcel-React-Templates

5. 总结

随着前端工程化这一概念深入人心,学会配置 webpack 打包、优化文件是非常重要的,这也是每个前端工程师都应该掌握的知识。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注