• 基于webpack的React项目搭建(二)


    前言

    前面我们已经搭建了基础环境,现在将开发环境更完善一些。

    • devtool

    在开发的过程,我们会经常调试,so,为了方便我们在chrome中调试源代码,需要更改webpack.config.js,然后启动webpack-dev-server。完成之后在chrome浏览器中打开debug,点击Sources选项,即可看见提示,继而输入你想查看的源文件名即可显示该文件源代码,如果你觉得某处代码有问题,对应行号打上断点即可调试。

    ......
    module.exports = {
        devtool: 'cheap-module-eval-source-map',
        ......
     }

    • 热更新(HMR)

    HMR应该是webpack令人非常兴奋的一个特点,它在代码修改后重新打包并发送到浏览器,浏览器将获取的新模块替换老模块,在不刷新浏览器的情况下实现对应用的更新。由于我们使用的是webpack-dev-server,它提供了两种自动刷新方式供我们选择,iframe和inline模式。这里我们选择inline模式,更改dev-server.js。

    ......
    const server = new WebpackDevServer(compiler, { contentBase: path.resolve(__dirname, '../build'), // 默认会以根文件夹提供本地服务器,这里指定文件夹 inline: true, // 自动刷新 hot: true, // 开启热模块替换
    ......

     更改webpack.config.js

    ......
    const webpack = require('webpack');
    module.exports = { devtool: 'cheap-module-eval-source-map', entry: [
         
    'webpack-dev-server/client?http://localhost:9090', 'webpack/hot/only-dev-server', path.resolve(__dirname, '../src/index.js') ],
       ...... plugins: [
    new webpack.HotModuleReplacementPlugin()
         ...... ]

     最后更改index.js

    import React from 'react';
    import { render } from 'react-dom';
    import App from './App'
    
    const renderDom = Component => {
        render(
            <Component />,
            document.getElementById('app')
        );
    }
    renderDom(App);
    
    if (module.hot) {
        module.hot.accept('./App', () => {
            const App = require('./App').default;
            renderDom(App);
        })
    } 

    接下来执行npm run dev,查看浏览器,发现如下就实现了热更新。

    然后修改App.js里render返回的html,保存后可以发现浏览器会自动刷新并看到你更改后的效果。也许这样就实现了React组件的热更新,Right ?我们对App.js做如下更改看看会有什么变化。

    import React, { Component } from 'react';
    
    export default class App extends Component {
        constructor(props) {
            super(props);
            this.state = {
                count: 1,
            }
        }
    
        add () {
            this.setState({ count: this.state.count + 1 });
        };
        render() {
            return (
                <div>
                    <h1>{this.state.count}</h1>
                    <button onClick={() => this.add()}>增加1</button>
                </div>
            );
        }
    }

    然后在浏览器中点击按钮,页面中数值随之增加。然后,我们修改一下App.js(在button标签下增加其他标签),保存后浏览器自动刷新。我们查看一下浏览器,那么问题来了,刚刚点击增加后的数值不见了,又回到了初始值1。这时候发现组件的状态并没有保存下来,没有达到真正意义上的React热更新。所以这里还需要引入一个插件,来帮我们解决热更新组件状态保存问题。这也是react-hot-loader的由来。

    npm install react-hot-loader --save-dev
    npm install babel-polyfill --save

     更改webpack.config.js。

    ......
    module.exports = { devtool: 'cheap-module-eval-source-map', entry: [ 'babel-polyfill', 'react-hot-loader/patch', 'webpack-dev-server/client?http://localhost:8080', 'webpack/hot/only-dev-server',
    ......

     更改index.js。

    ......
    import { AppContainer } from 'react-hot-loader'; import 'babel-polyfill'
    ; import App from './App'; const renderDom = Component => { render( <AppContainer> <Component /> </AppContainer>, document.getElementById('app') ); };
    ......

     更改.babelrc。

    {
      "presets": [
        [
          "es2015",
          {
            "module": false
          }
        ],
        "react"
      ],
      "plugins": [
        "react-hot-loader/babel"]
    }

    修改完后,需要重新执行npm run dev。我们重复上面的操作,可以发现,没有再出现上面的问题。当然上面的React函数绑定还有多种写法:

    //方式一
    <button onClick={() => this.add()}>增加1</button>
    
    //方式二
    <button onClick={this.add.bind(this)}>增加1</button>
    
    //方式三,官方推荐使用
    constructor(props) {
        super(props)
        this.add = this.add.bind(this);
    }
    <button onClick={this.add)}>增加1</button>
    //方式四,推荐(由于处于草案阶段,所以是以插件的方式使用)
    add = () => {
      ......
    } <button onClick={this.add)}>增加1</button>

    我更倾向于第四种,更简洁。这里我们配置一下第四种方式。

    npm install babel-preset-stage-1 --save  

     最后修改.babelrc即可。

    ......
    "react", "stage-1"
    ......
    •  ESLint语法校验

      一个JavaScript语法检测工具,可以像IDE一样静态检测代码错误并提示。首先安装eslinteslint-loader

    npm install eslint eslint-loader --save-dev

       修改webpack.config.js。

    ......
    module: { rules: [ { enforce:
    "pre", test: /\.(js|jsx)$/, loader: 'eslint-loader', exclude: /node_modules/ },
    ......

      项目根目录下新建.eslintrc.json。

    {
      "rules": {
    
      }
    }

      我们先不创建规则,直接运行会报error Parsing error: The keyword 'import' is reserved,因为项目中使用了es6等新语法,而这些还不能被直接识别,所以还需安装babel-eslint进行转义。

    npm install babel-eslint --save-dev
    

      修改.eslintrc.json文件。

    {
      "parser": "babel-eslint",
      "rules": {
    
      }
    }

      上述修改完后,就可以重新运行了。到这里,我们可以开始自定义规则,你可以将自己的规则开源出来供大家一起使用。然而要从头到尾全部自定义规则并不切合实际,所幸已经有很多符合最佳实践的规则。这里我们选择Airbnb,安装eslint-config-airbnb(推荐)。

    npm install eslint-config-airbnb --save-dev
    

      eslint-config-airbnb需要下面3个插件的支持:

    npm install eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react --save-dev
    

      修改.eslintrc.json,暂时加入以下规则。

    {
      "parser": "babel-eslint",
      "extends": "airbnb",
      "env": {
        "browser": true,
        "node": true,
        "es6": true
      },
      "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module",
        "ecmaFeatures": {
          "jsx": true
        }
      },
      "plugins": [
        "react"
      ],
      "rules": {
        "react/jsx-no-bind": [
          "error",
          {
            "ignoreRefs": true,
            "allowArrowFunctions": true,
            "allowBind": true
          }
        ],
        "import/no-extraneous-dependencies": "off",
        "react/jsx-filename-extension": "off"
      }
    }

      配置好后重新运行,发现红了一片(很多错)。别急,我们一步一步修改。首先修改index.js,在文件头部加上/*eslint-disable*/,不对index.js进行校验。剩余的我们就不一一更改了,可以让IDE(Webstorm)为我们修改。选择WebStorm的Preferences,搜索ESLint,将我们创建的规则应用到项目中。

      然后在报错的文件中,点击红色感叹号,点击第一项,即可自动修改错误。

    •  其他常用加载器

      其他常用加载器还有很多,这里简单将css配置了一下,其余就不一一配置介绍了,请自行按需配置。最后webpack.config.js配置如下。

        css-loader: 解析css代码

        style-laoder: 将编译后css样式导入到html中

        less-loader: 加载和转移less文件

        raw-loader: 加载文件原始内容(utf-8格式)

        url-loader: 多用于加载图片

        file-loader: 打包文件

    const path = require('path');
    const webpack = require('webpack');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      devtool: 'cheap-module-eval-source-map',
      entry: [
        'babel-polyfill',
        'react-hot-loader/patch',
        'webpack-dev-server/client?http://localhost:9090',
        'webpack/hot/only-dev-server',
        path.resolve(__dirname, '../src/index.js'),
      ], // 指定入口文件,程序从这里开始编译,__dirname当前目录, ../表示上一级目录, ./同级目录
      output: {
        path: path.resolve(__dirname, '../dist'), // 输出的路径
        filename: 'app/[name]_[hash:8].js', // 打包后文件
      },
      module: {
        rules: [
          {
            enforce: 'pre',
            test: /\.(js|jsx)$/,
            loader: 'eslint-loader',
            exclude: /node_modules/,
          },
          {
            test: /\.(js|jsx)$/,
            loader: 'babel-loader', // 加载器
            exclude: /node_modules/,
          },
          {
            test: /\.css$/,
            use: [{
                loader: 'style-loader'
            }, {
                loader: 'css-loader'
            }],
          },
          {
            test: /\.less$/,
            use: [{
              loader: 'style-loader',
            }, {
              loader: 'css-loader',
            }, {
              loader: 'less-loader',
              options: {
                sourceMap: true,
              },
            }],
          },
        ],
      },
      plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, '../src/index.template.html'),
          inject: true,
        }),
      ],
    }; 
  • 相关阅读:
    C#单纯的字母数字ASCII码转换
    解析类型后加问号和双问号
    【转】composer autoload 自动加载性能优化指南
    【转】Laravel 三种中间件作用讲解
    【转】Laravel belongsTo 详解
    【转】docker-compose详解
    【转】laravel之Artisan命令操作Artisan Console
    【转】Shell中>/dev/null 2>&1 详解
    【转】docker-entrypoint.sh 文件的用处
    【转】解决Debian下sudo命令unable to initialize PAM问题
  • 原文地址:https://www.cnblogs.com/raion/p/8111396.html
Copyright © 2020-2023  润新知