从零到一搭建 react 项目系列之(四)

简介: 介绍如何搭建开发环境之热更新。

前言


上一篇文章介绍了如何打包成 HTML 文件,接着我们将介绍如何搭建开发环境之热更新


正文


使用 source-map


如果按照默认的 production 模式打包代码是,可能会很难追踪错误和警告在源代码中的原始位置。例如,如果将三个源文件(a.js, b.jsc.js)打包到一个 bundle(bundle.js)中,而其中一个源文件包含一个错误,那么堆栈跟踪就会直接指向到 bundle.js。你可能需要准确地知道错误来自于哪个源文件,所以这种提示这通常不会提供太多帮助。


为了更容易地追踪 error 和 warning,JavaScript 提供了 source maps 功能,可以将编译后的代码映射回原始源代码。如果一个错误来自于 b.js,source map 就会明确的告诉你。


source map 有许多可用选项,请务必仔细阅读它们,以便可以根据需要进行配置。

对于本指南,我们将使用 eval-source-map 选项,这有助于解释说明示例意图(此配置仅用于示例,不要用于生产环境)


选择一个工具


在每次编译代码时,手动运行 yarn run build 会显得特别麻烦。

webpack 提供了几种可选方式,帮助我们在代码发生变化后自动编译代码:


  • webpack watch mode(webpack 观察模式)
  • webpack-dev-server
  • webpack-dev-middleware


webpack 可以在 watch mode(观察模式)下使用。在这种模式下,webpack 将监视您的文件,并在更改时重新编译。


webpack-dev-server 提供了一个易于部署的开发服务器,具有快速的实时重载(live reloading)功能。


如果你已经有一个开发服务器并且需要完全的灵活性,可以使用 webpack-dev-middleware 作为中间件。


webapck-dev-serverwebpack-dev-middleware 使用内存编译,这意味着 bundle 不会被保存在硬盘上。这使得编译十分迅速,并导致你的文件系统更少麻烦。

在大多数情况下你会想要使用 webpack-dev-server,因为这是最简单的开始的方式,并且提供了很多开箱即用的功能。本项目中也将会使用到它。


简单配置 webpack-dev-server

# 安装
$ yarn add webpack-dev-server@3.9.0 --dev
// 修改 webpack.config.js 配置
devServer: {
  contentBase: './dist',
  open: true
}
// 在 package.json 添加 npm script
"scripts": {
    "dev": "webpack-dev-server --config webpack.config.js --colors"
}


以上配置告知 webpack-dev-server,将 dist目录下的文件 servelocalhost:8080 下。(译注:serve,将资源作为 server 的可访问文件)。

现在,在命令行中运行 yarn run dev,我们会看到浏览器自动加载页面。如果你更改任何源文件并保存它们,web server 将在编译代码后自动重新加载。

但是同时可以观察到一个细节,每次更改文件页面会重新加载,但是这应该不是我们想要的,我们想要的是模块热替换hot module replacement)。


HMR 模块热替换配置


*首先它不适用于生产环境,仅应用于开发环境。


模块热替换功能会在应用程序运行过程中,替换、添加或删除模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:

  • 保留在完全重新加载页面期间丢失的应用程序状态。
  • 只更新变更内容,以节省宝贵的开发时间。
  • 在源代码中 CSS/JS 产生修改时,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。

// webpack.config.js
const config = {
  // ... 其他已有配置不变
  devServer: {
    contentBase: './dist',
    hot: true,
    open: true
  },
  plugins: [
    // 在 webpack 4 中其实已被弃用,取代它的是 optimization.namedModules 后续的文章会讲解到
    // new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ]
}


我们在入口文件 index.js 引入 main.js

// main.js
console.log('This is main.js')


我们来修改 index.js文件,以便当 main.js 内部发生变更时可以告诉 webpack 接受更新的模块。

// index.js
import './main.js'
console.log('Hello Webpack!')
if(module.hot) {
    module.hot.accept('./main.js', () => {
        console.log('Accept update!')
    })
}


注意,若修改了 webpack 配置文件,我们需要重新执行 yarn run dev 使其生效。


当我们修改 main.js 按下保存之后,会看到浏览器控制台会输出以下信息:

[WDS] App updated. Recompiling...
[WDS] App hot update...
[HMR] Checking for updates on the server...
This is main.js.
We modified the main.js file.
Accept update!
[HMR] Updated modules:
[HMR]  - ./src/main.js
[HMR] App is up to date.


HMR 加载样式


借助于 style-loader,使用模块热替换来加载 CSS 实际上极其简单。此 loader 在幕后使用了 module.hot.accept,在 CSS 依赖模块更新之后,会将其 patch(修补) 到 <style> 标签中。


在此之前,我们说过 webpack 只能读取 JavaScript 和 JSON 文件,其他类型的文件需要借助对应的 loader 来处理。


首先使用以下命令安装两个 loader 。

$ yarn add --dev css-loader@3.2.0 style-loader@1.0.0


更新 webpack 配置文件

// webpack.config.js
const config = {  
  module: {
    rules: [
      {
        test: /\.css/,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
}
module.exports = config


我们在 src 目录下新增 style.css 文件,并在 index.js 中引入。

/* style.css */
body {
    font-size: 30px;
}

// index.js
import './main.js'
import './style.css'
console.log('Hello Webpack!')
if(module.hot) {
    module.hot.accept('./main.js', () => {
        console.log('Accept update!')
    })
}


然后我们试着修改 style.css 的样式,就能看到页面字体大小随之更改,而无需完全刷新。


至此


我们最简单的 HMR 已经配置好了,接着我们将会介绍接入 React 。


最后附上

// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')
const config = {
  mode: 'development',
  devtool: 'eval-source-map',
  entry: {
    index: path.resolve(__dirname, './src/index.js')
  },
  devServer: {
    contentBase: './dist',
    hot: true,
    open: true
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: '开发环境', // 模板要使用 <title><%= htmlWebpackPlugin.options.title %></title> 配置才生效
      template: './src/index.html', // 模板路径
      filename: 'index.html', // 输出 HTML 文件名称
      inject: 'body', // 插入的 script 标签位于 body 底部,true 同理
      hash: true, // 加上 hash 值
      favicon: './src/favicon.ico'
    }),
    // 新版无需再指定删除目录,默认删除 output 目录
    new CleanWebpackPlugin(),
    // 热更新
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ],
  module: {
    rules: [
      {
        test: /\.css/,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
}
module.exports = config

// index.js
import './main.js'
import './style.css'
console.log('Hello Webpack!')
if(module.hot) {
    module.hot.accept('./main.js', () => {
        console.log('Accept update!')
    })
}

// 当前项目目录
webpack4_demo
  | - /assets
  | - /config
  | - /dist
    | - some outputh file
  | - /src
    | - favicon.ico
    | - index.html
    | - index.js
    | - main.js
    | - styles.css
  | - .gitignore
  | - package.json
  | - README.md
  | - webpack.config.js
  | - yarn.lock


目录
相关文章
|
6月前
|
前端开发 JavaScript 测试技术
从零开始搭建react+typescript+antd+redux+less+vw自适应项目
从零开始搭建react+typescript+antd+redux+less+vw自适应项目
179 0
|
6月前
|
前端开发 API 数据安全/隐私保护
【第45期】一文解决React项目的权限管理
【第45期】一文解决React项目的权限管理
331 0
|
6月前
|
Web App开发 资源调度 JavaScript
竟然可以在一个项目中混用 Vue 和 React?
竟然可以在一个项目中混用 Vue 和 React?
650 0
|
6月前
|
运维 JavaScript 前端开发
发现了一款宝藏学习项目,包含了Web全栈的知识体系,JS、Vue、React知识就靠它了!
发现了一款宝藏学习项目,包含了Web全栈的知识体系,JS、Vue、React知识就靠它了!
|
6月前
|
存储 JSON 前端开发
react保姆级搭建新项目
此文主要以ts+vite+router6+antd 快速搭建一个react项目,适用于初学者,用于学习交流
107 2
|
6月前
|
移动开发 JavaScript 前端开发
vue/react项目刷新页面出现404的原因以及解决办法
vue/react项目刷新页面出现404的原因以及解决办法
681 0
|
6月前
|
存储 资源调度 前端开发
【React | 完整项目创建流程】能看到这么详细的React配置流程,就偷着乐吧!
【React | 完整项目创建流程】能看到这么详细的React配置流程,就偷着乐吧!
211 1
|
6月前
|
前端开发 JavaScript API
Github 上 8 个很棒的 React 项目
Github 上 8 个很棒的 React 项目
1468 0
|
6月前
|
前端开发 开发工具 git
React项目包结构的作用
React项目包结构的作用
113 0
|
6月前
|
前端开发
React 中 react-i18next 切换语言( 项目国际化 )
React 中 react-i18next 切换语言( 项目国际化 )
593 0