#ReactApp項目構建流程【3】

幫助程序員簡化流程,專一業務代碼的webpack配置

3.1項目中頗有用的webpack經常使用配置

在傳統html開發流程中,webapp開發模式中,前端代碼改動不少,按照以前的流程跑的話,每次都須要npm run build以及run start,開發流程就會很繁瑣javascript

webpack dev server

webpack官方插件,經過webpack配置去啓動一個微型服務器,便於開發者在開發過程當中避免沒必要要的build以及start,而且該服務器編譯出來的內容保存於內存中,一旦內容有更新,都會自動執行build,而不用手動buildhtml

Hot module replacement

編輯工程時,幫助咱們在修改代碼後,頁面實時更新[區別於會從新請求頁面的「刷新」]前端

  • 免於手動刷新查看頁面效果
  • webapp開發模式會在前端中存儲大量數據,若是沒有實時刷新,那麼每次手動刷新時數據都會從新請求一遍,時間很是浪費,Hot module replacement能夠保持當前狀態,無需從新請求數據

3.2具體配置__webpack dev server

  • 想仔細瞭解可去webpack官網查閱

  • 由於上述配置只用於開發環境,因此須要判斷當前執行環境,須要在webpack.config.client.js中添加如下代碼

    //添加執行環境判斷變量【NODE_ENV】
    const isDev=process.env.NODE_ENV==='development';
    //修改
    module.exports={...}
    ->    const config={...}
    //在最後加入
    if(isDev){
        config.devServer={        //devServer而不是server
            host:'0.0.0.0',//兼容localhost,0.0.0.0,以及IP三種方式訪問
            port:'3000',   //webpack微服務端口(之後都稱爲devServer)
            contentBase:path.join(__dirname,'../dist'),//靜態文件路徑
            hot:true,       //是否開啓Hot module replacement
            overlay:{       //網頁何時出現遮罩警告層,這裏配置爲error時
                errors:true //還有多種,好比warning,可是通常會過濾掉其餘類型
           }
        }
    }
    module.exports=config;      //不是modules也不是export也不是(config)...
  • $npm i webpack-dev-server -D

  • 安裝完成後在package.json中添加啓動微服務的script

    scripts->
    "dev:client":"cross-env NODE_ENV=development && webpack-dev-server --config build/webpack.config.client.js"    //手誤寫成server.js
    //上面判斷執行環境時,使用的【NODE_ENV】就是這裏定義的變量【NODE_ENV】
    //cross-env是一個咱們須要安裝的包,用於兼容windows,linux以及mac的命令行
  • $npm i cross-env -D

  • $npm run dev:client

    • 進入瀏覽器訪問,查看http請求,發現請求文件有404,查看請求url,發現路徑多了public,須要在配置devServer時進行處理
    • 具體緣由:webpack.config.client.js->devServer->contentBase的value表示啓動devServer在value目錄下,也就是說devServer的root是dist目錄,而dist目錄是真正的項目ROOT的一個子節點,而client被output出去時使用的是靜態資源文件路徑是添加上了publicPath的value--'/public'
    • 解決方法:在devServer中添加配置:java

      publicPath:'/public',       //訪問靜態資源時都須要添加public
      historyApiFallback:{        
      //爲咱們自動配置了不少映射關係,單頁應用的全部url都會返回404,而該配置將全部前端返回的404請求都返回成historyApiFallback的index
          index:'/public/index.html' //指定index,由於publicPath添加了前綴,因此此處也須要添加前綴
      }
  • $npm run dev:client

    • 配置完後仍然會有404,由於devServer會檢測硬盤是否有此目錄,有時會以硬盤爲準而非內存中編譯文本的內容爲準。
    • 刪除dist目錄,從新$npm run dev:client,此時報錯:
      Uncaught Error: [HMR] Hot Module Replacement is disabled.
      【緣由】:在devServer中開啓了hot:true,可是並無安裝相關依賴模塊致使引用相關js文件shi出錯
      【解決】:暫時註釋掉hot:true,從新 $npm run dev:client
    • 小優化:
      將template.html中的<app>標籤修改成html註釋<!--app-->,而後在server端渲染時,由替換非標準html標籤<app>修改成替換註釋,由於註釋不會被瀏覽器編譯,天然不會判斷出錯
  • 修改代碼會發現瀏覽器實現內容自動刷新(爲實現自動更新須要配置hot-module-replacement)

3.3具體配置__Hot-module_replacement

* `.babelrc`添加`presets`同級KV
    "plugins":["react-hot-loader/babel"]
    
* `$npm i react-hot-loader@next -D`
    @next是由於當前爲測試版,還沒有正式發佈到npm中
    
* `app.js`加入如下內容,[個人第2篇文章](https://segmentfault.com/a/1190000012945475)
    ```
    if(module.hot){    //當咱們須要熱更新的代碼有更新時,從新加載App
    module.hot('./App.jsx',()=>{
        const NextApp=require('./App.jsx').default;//加default的緣由在上面連接中有提到
        ReactDOM.hydrate(<NextApp />,document.getElementById('root'));
        })
    }
    
* `$npm run dev:client`
    ```
    發現頁面仍然會自動刷新,沒有實現
     
* `client配置中`
    ```
    hot:true解註釋
    const webpack=require('webpack')
    //頂部引入webpack
    config.plugins.push(new Webpack.HotModuleReplacementPlugins());
    //與config.devServer同級添加webpack的HotModuleReplacementPlugins插件    
    //因爲在.babelrc中添加了hotmodule配置,須要在開發時修改entry,因爲只是在開發是進行修改,因此config.devServer中進行修改便可:
    config.entry={
        app:[
            'react-hot-loader/patch',
            //客戶端熱更新代碼時須要用到的補丁包
            path.join(__dirname,'./client/app.js')
            //要打包的內容
        ]//webpack的entry能夠是個數組,表明着該entry中引用的文件,webpack在打包時會將全部的文件打包在一個文件中
    }
    

    import React from 'react'
    import ReactDOM from 'react-dom'
    import { AppContainer } from 'react-hot-loader'
    //更新1:使用AppContainer去包裹咱們的根節點想要渲染的實際HTML內容
    import App from './App.jsx'
    
    //ReactDOM.hydrate(<App />,document.getElementById('root'));
    //更新2:封裝成可傳遞參數的方法,此處註釋掉
    //將App掛載在document.body中,由於此時並無模板,只有body可使用,官方推薦在body中建立一個默認節點做爲主dom
    
    const root=document.getElementById('root');
    //更新3:根節點變量化
    const render = Component =>{
        const renderMethod=module.hot ? ReactDOM.render :ReactDOM.hydrate;
        //注意點!
        //若是不對是否採用react-hot-loader進行判斷,npm run dev:client時,進入瀏覽器會彈出錯誤
        //Warning: Expected server HTML to contain a matching <div> in <div>.
        renderMethod(
            <AppContainer>
                <Component />
            </AppContainer>,
                root
        )
    };
    //更新4:更新2的封裝
    render(App);
    //更新5:傳參調用更新4
    if(module.hot){
        module.hot.accept('./App.jsx',()=>{
            const NextApp=require('./App.jsx').default;
            
            //ReactDOM.hydrate(<App />,document.getElementById('root'));
            //更新6,採用封裝方法,此處註釋
            render(NextApp)
            //更新7,傳參調用更新4
        })
    }
    

* `npm run dev:client`
    進入瀏覽器,修改內容,發現無需刷新便可更新內容,可是更新時間比較長,
        想要更快更新,須要手動保存CTRL+S
    另外,【若是】手動重啓devServer後hotmodule失效(頁面Elements刷新),
    打開network,勾選Preserve log(用於保留刷新前的請求內容,防止刷新後之前的請求丟失致使很差定位問題),
    修改內容後查看請求url,發現404請求,url樣式:
        http://localhost:3000/public6f45a1f9b1cb390b0ffb.hot-update.json
        該文件通知hotmodule有模塊更新以更新內容,發現public後缺失"/",須要在修改成
    publicPath:'/public/',推薦後面都加上'/',
    多'/'不會出現路徑錯誤,少'/'卻會在某些時候引起不可預期的錯誤

小結

  • 多配置,多看官方文檔,熟練各類配置,不然坑太多
相關文章
相關標籤/搜索