美文网首页从零到一搭建 React 项目
从零到一搭建 react 项目系列之(四)

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

作者: 越前君 | 来源:发表于2020-08-20 09:13 被阅读0次

    上一篇文章介绍了如何打包成 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
    

    相关文章

      网友评论

        本文标题:从零到一搭建 react 项目系列之(四)

        本文链接:https://www.haomeiwen.com/subject/llrdjktx.html