react源碼閱讀環境配置

前言

閱讀源碼時,有許多變量在程序運行過程當中不斷的產生,其中存放着什麼東西,一直是一個比較頭疼的問題。不停的推導增長了驗算的負擔,隨着代碼逐漸的深刻,也會產生必定的記憶負擔。若是靠腦殼去記,簡單點的代碼還好。複雜的代碼。。。你懂的。
隨着react被普遍使用,不少人會好奇react是怎麼實現的。會有一探源碼的想法。若是直接閱讀react.development.js是很簡單,頁面引入就行了。可是react.development.js終因而通過編譯工具編譯過的代碼,不少的代碼看起來並不直觀。理想的狀況是直接引用源文件,也就是github上react倉庫中,packages目錄下的代碼,直接閱讀es6的代碼。
可是es6代碼瀏覽器支持並不友好。因此須要配置webpack打包成es5。同時須要配上sourceMap。這樣,既可讓源碼跑在瀏覽器環境,也能夠直接讀es6的代碼,並且能夠隨時打斷點,查看變量裏保存的值。css

那麼,閒言少敘,開始本章的主題。html

目錄結構

概述

這是我目前用的一個簡單的目錄結構。這次調試的代碼爲react 16.4.0node

詳情

  • node_modules 存放依賴的包
  • packages github上的packages文件夾直接拿來用
  • test-env 測試用的目錄react

    • index.js #引用react、react-dom的啓動文件
    • index.less
    • tpl.html # html模板文件

clipboard.png

webpack的配置

概要

webpack的配置就是常規的babel,和一堆loader。爲了提升打包速度,可使用Happypack插件。若是以爲速度還不夠快,能夠再引入DLLplugin。此處webpack的使用不是重點,在此只是簡單給出打包須要的基本配置
代碼以下:webpack

詳情

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
const os = require('os');
const HappyPack = require('happypack');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
module.exports = {
  mode: 'development',
  entry: './test-env/index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  module: {
    rules: [{
        test: /\.css$/,
        use: {
          loader: 'happypack/loader?id=happyLess',
        }
      },
      {
        test: /\.less$/,
        use: {
          loader: 'happypack/loader?id=happyLess',
        }
      },
      {
        test: /\.js$/,
        use: {
          loader: 'happypack/loader?id=happyBabel',
        }
      }
    ]
  },
  plugins: [
    
    new HtmlWebpackPlugin({
      template: './test-env/tpl.html'
    }), new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      __DEV__: true,
      NODE_ENV:JSON.stringify("development"),
      spyOnDev: false,
      spyOnDevAndProd: false,
      spyOnProd: false,
      __PROFILE__: true,
    }),
    new HappyPack({
        //用id來標識 happypack處理那裏類文件
      id: 'happyBabel',
      //如何處理  用法和loader 的配置同樣
      loaders: [{
        loader: 'babel-loader?cacheDirectory=true',
      }],
      //共享進程池
      threadPool: happyThreadPool,
      //容許 HappyPack 輸出日誌
      verbose: true,
    }),
    new HappyPack({
      //用id來標識 happypack處理那裏類文件
      id: 'happyLess',
      //如何處理  用法和loader 的配置同樣
      loaders: ['style-loader','css-loader','less-loader'],
      //共享進程池
      threadPool: happyThreadPool,
      //容許 HappyPack 輸出日誌
      verbose: true,
    }),
  ],
  devtool: "inline-source-map", // enum
  devServer: {
    contentBase: path.join(__dirname, 'test-env'),
    port: 9000,
    hot: true,
    overlay: true
  },
  resolve: {
    modules: [
      "node_modules",
      path.resolve(__dirname, "packages"),
      path.resolve(__dirname, "packages/shared")
    ],
    alias: {
      '@packages': path.resolve(__dirname, 'packages/'),
    }
  }
};

babel配置

{
  "presets": ["env","react","stage-0"],
}

入口文件

概述

爲了簡化項目流程,此處用了一個最簡單的tpl.html模板文件,經過webpackhtmlplugin引入了打包好後的帶sourcemap的js。
其中,js只是用react實現了一個簡單的Hello world而且用react-render渲染到頁面上。git

index.js

import './index.less';
import React, {Component} from '@packages/react';
import ReactDOM from '@packages/react-dom/index.js';

class Hello extends Component{
  constructor(){
    super();
    console.log('hello world');
  }

  render() {
    return <div>hello world</div>
  }
}

ReactDOM.render(<Hello></Hello>, document.getElementById('root'));

其中@packages是我在webpack中配置的路徑別名,對應packages目錄。es6

tpl.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="root">
    hello world;
  </div>
</body>
</html>

概述

至此,環境已經配的差很少了。只是實際運行的時候仍是須要安裝一些包。此處忽略了裝包的過程。可是實際項目運行中控制檯仍是報了一些錯。其中一個最糾結的地方github

This module must be shimmed by a specific renderer.

自環境配好後我遇到的第一個問題是這句話。起初覺得是react的問題。糾結了好幾個小時候,才找到了問題的根源。web

問題並不來react這個包

既然問題不是react,那來自哪裏呢。沒錯,來自react-dom,由於頁面上總共就引用了兩個包,非react則react-domjson

問題解決思路

經過錯誤信息處函數調用堆棧能夠看出,該錯誤來源於一個ReactFiberHostConfig.js中。雖然不知道這裏爲何會有這個,可是仍是想去源倉庫找找答案。看了react官方實際使用了rollup去打包代碼。可是rollup裏一大坨看不懂得代碼。那怎麼辦呢。去搜索這個hostconfig.js是什麼鬼。

貌似的答案

react爲了實現將一樣的結構,render到不一樣的平臺,使用了react-reconciler作了一箇中間層。提供接口可讓用戶自定義render的實現,而且給出了一個render-dom的示例。可是無論使用哪一種render,都要提供一個hostconfig,源碼中這個react-reconciler文件夾中引用的config老是會拋出一段錯誤,可是實際上,正確的config已經在文件夾中給出,只要將拋錯這段代碼給替換成引用正確的config便可。

概括總結

錯誤調用棧 react-dom-》react-reconciler-》hostconfig error

解決

react-reconclier中src下的ReactFiberHostConfig中的報錯改成引用正確的config。貼上引用代碼
export * from './forks/ReactFiberHostConfig.dom';

完結撒花

至此已經能夠在瀏覽器中調試es6版本的react代碼。不過這個環境配置過程當中並不是一路順風。首先遇到錯首先覺得是react的問題。糾結了好幾個晚上(下班後纔開始想),網上查閱了不少資料,也沒想出因此然,最後發現是react-dom的問題,也糾結了很久,最終終於配起了這套環境。

喜歡的朋友點個贊哈。謝謝支持。

相關文章
相關標籤/搜索