#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/',推荐后面都加上'/',
    多'/'不会出现路径错误,少'/'却会在某些时候引起不可预期的错误

小结

  • 多配置,多看官方文档,熟练各类配置,不然坑太多
相关文章
相关标签/搜索