基於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,
    }),
  ],
}; 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM