Webpack打包React踩到的坑


  學習React斷斷續續地也有兩三周了,期間接觸到了一大堆名詞和工具,不得不承認React生態圈實在是太繁榮了,作為還沒畢業的學生,本應該沉下心來多看看基礎課程、刷一刷面試題好在秋招找一份不錯的工作,但是一想到還有那么多好玩的框架沒有學過,好用的工具沒有用過,就心里直癢癢~

  剛剛解決了困擾了我好一段時間的問題,在網上查了好多資料都沒找到,趁着中午休息時間記錄下來吧。

  需求:公司項目使用APICloud將前端代碼打包成原生應用,並使用React將應用組件化  

  問題:如何在本地直接打開html呈現React頁面?

  下面簡單介紹一下產生這個問題的源頭:

  初學React時因為代碼量較小,而且重點在學習語法,所以組件都是寫在index.html里內聯的script標簽里,在<head>里使用browser.js將jsx語法轉換為js,這樣顯然不利於模塊化和復用,並且所有的組件內部都呈現在主頁,很丑陋。

  那怎么解決呢?首先想到的是將組件代碼以<script type="text/babel" src="xx.jsx" />的方式引入,但是在chrome下browser.js報跨域錯,據說改下chrome的跨域配置或換用Firefox可以正常運行,但因為不是解決問題本身,沒有太大意義,就沒有嘗試。  

  在知乎中看到有人回答類似問題,說這不是React正確的打開姿勢,要在本地起一個服務器,將項目部署到React上即可。於是接觸到了webpack,不得不說webpack很全能,也很強大,從css預處理,到js混淆,圖片引用,只要配置得當,它全能幫你做好,這里webpack的配置文件等推薦使用Yeoman的generator-react-webpack自動生成,當初不知道這些工具,查文檔一項一項調試真是吐血。。。總算配好了環境,可以開始愉快地開發了,所有的components自成文件,在需要的時候引入即可,各種依賴由webpack幫你完成,npm start 自動起一台支持熱插拔、自動刷新的服務器,加上React-router以后也算個像模像樣的SPA了。

  然而……項目中的前端部分要作為靜態資源打包到APICloud,這就意味着在瀏覽器環境下(無服務器)的情況下,雙擊index.html要能呈現出和webpack-dev-server一樣的效果,有了初學時的思維定式,這個問題一下子難住了我(其實現在想想好簡單哦),用過webpack-dev-server的同學應該都知道,webpack熱部署的原理是將index.html中引用的本地文件的路徑替換為存放在內存中的實時編譯的bundle.js文件,每當源文件發生改變,就重新編譯改變的部分並重新加載到內存中。想要將項目本地化,首先就是將bundle.js寫入文件系統(在generator-react-webpack生成的項目的默認配置下),命令如下

npm run --dev=dist

這時,所有的源文件以及依賴會被編譯並存放到dist目錄下,打開dist/index.html,竟然啥也沒有!!!一夜回到解放前,打開chrome元素面板,<div id="app"></div>里啥也沒,我暈,打開編譯+混淆后的bundle.js看了十幾分鍾,在入口處console.log幾句話也都打出來了,就是render函數沒效果,難道真的像知友說的那樣打開姿勢不對?React不能在本地跑?我才不信,回到webpack配置文件,去掉UglifyJsPlugin插件,重新編譯,再看編譯+未混淆的代碼

_reactDom2.default.render(_react2.default.createElement(
        _reactRouter.Router,
        { history: _reactRouter.browserHistory },
        _react2.default.createElement(
            _reactRouter.Route,
            { path: '/', component: _Main2.default },
            _react2.default.createElement(_reactRouter.IndexRoute, { component: _LoginPage2.default }),
            _react2.default.createElement(_reactRouter.Route, { path: 'login', component: _LoginPage2.default }),
            _react2.default.createElement(
                _reactRouter.Route,
                { onEnter: requireLogin, path: 'student', component: _Student2.default },
                _react2.default.createElement(_reactRouter.IndexRoute, { component: _Info2.default }),
                _react2.default.createElement(_reactRouter.Route, { path: 'books', component: _BookList2.default })
            ),
            _react2.default.createElement(
                _reactRouter.Route,
                { path: 'admin', component: _Admin2.default },
                _react2.default.createElement(_reactRouter.IndexRoute, { component: _Info2.default }),
                _react2.default.createElement(_reactRouter.Route, { path: 'books', component: _BookList2.default })
            )
        )
    ), document.getElementById('app'));

噗。。一眼就看到了browserHistory,原來繞了一大圈子,還是服務器的鍋,原來,我的項目使用了browserHistory做路由的history,而browserHistory本身就是依賴服務器的,如果要在本地跑,換成hashHistory應該就好了,重新編譯,測試,通過,這下子,終於可以專心學習React本身了!

 


免責聲明!

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



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