閱讀源碼時,有許多變量在程序運行過程當中不斷的產生,其中存放着什麼東西,一直是一個比較頭疼的問題。不停的推導增長了驗算的負擔,隨着代碼逐漸的深刻,也會產生必定的記憶負擔。若是靠腦殼去記,簡單點的代碼還好。複雜的代碼。。。你懂的。
隨着react被普遍使用,不少人會好奇react是怎麼實現的。會有一探源碼的想法。若是直接閱讀react.development.js是很簡單,頁面引入就行了。可是react.development.js終因而通過編譯工具編譯過的代碼,不少的代碼看起來並不直觀。理想的狀況是直接引用源文件,也就是github上react倉庫中,packages目錄下的代碼,直接閱讀es6的代碼。
可是es6代碼瀏覽器支持並不友好。因此須要配置webpack打包成es5。同時須要配上sourceMap。這樣,既可讓源碼跑在瀏覽器環境,也能夠直接讀es6的代碼,並且能夠隨時打斷點,查看變量裏保存的值。css
那麼,閒言少敘,開始本章的主題。html
這是我目前用的一個簡單的目錄結構。這次調試的代碼爲react 16.4.0
node
test-env 測試用的目錄react
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/'), } } };
{ "presets": ["env","react","stage-0"], }
爲了簡化項目流程,此處用了一個最簡單的tpl.html模板文件,經過webpackhtmlplugin引入了打包好後的帶sourcemap的js。
其中,js只是用react實現了一個簡單的Hello world而且用react-render渲染到頁面上。git
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
<!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
自環境配好後我遇到的第一個問題是這句話。起初覺得是react的問題。糾結了好幾個小時候,才找到了問題的根源。web
既然問題不是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的問題,也糾結了很久,最終終於配起了這套環境。
喜歡的朋友點個贊哈。謝謝支持。