美文网首页饥人谷技术博客
关于webpack的react项目优化

关于webpack的react项目优化

作者: 贝伟强 | 来源:发表于2017-06-01 09:43 被阅读0次

    这几天有空给自己写的一个react小项目的webpack配置进行优化,在这里进行一下总结。
    项目地址:https://github.com/beiweiqiang/myh5

    我把这个项目的开发环境和生产环境各写了一份webpack.config,用一个总的 webpack.config.js 进行switch:

    // webpack.config.js
    const webpackProduction = require('./webpack.prod.js');
    const webpackDevelopment = require('./webpack.dev.js');
    
    
    const isProduction = process.env.NODE_ENV === 'production';
    
    process.noDeprecation = true;
    
    module.exports = isProduction ? webpackProduction : webpackDevelopment;
    

    对开发环境进行判断,switch合适的webpack配置。

    我们先说开发环境,因为是react项目,开发环境用到了hmr,要用hmr,在项目入口处的代码还要进行一定的配置,下面是官方例子:

    import React from 'react';
    import ReactDOM from 'react-dom';
    
    import { AppContainer } from 'react-hot-loader';
    // AppContainer 是一个 HMR 必须的包裹(wrapper)组件
    
    import App from './components/App';
    
    const render = (Component) => {
      ReactDOM.render(
        <AppContainer>
          <Component/>
        </AppContainer>,
        document.getElementById('root')
      );
    };
    
    render(App);
    
    // 模块热替换的 API
    if (module.hot) {
      module.hot.accept('./components/App', () => {
        render(App)
      });
    }
    

    这里我在开发过程中有一个bug,就是console上虽然说了 app up to date,但是chrome浏览器自身不会进行自动刷新,经过google以后得到解决方案。
    把最后部分改成下面这样就行:

    // 模块热替换的 API
    if (module.hot) {
      module.hot.accept();
    }
    

    说回开发环境下的webpack配置,因为代码有点长,所以就不贴在这里,可以参考我的项目webpack.dev.js 文件。
    说几个地方:

    1

    output: {
        path: path.resolve(__dirname, 'client', 'dist'),
        // filename: '[name].[chunkhash].js',
        filename: '[name].js',
        publicPath: '/',
      }
    

    这里并没有像生产环境下的webpack配置 (下面会介绍) 一样给文件加上hash值,因为计算这个hash会耗费时间,开发环境讲究构建速度要快,所以不需要这个hash值。

    2
    devtool: 'inline-source-map' 开启 source-map

    3

    devServer: {
        historyApiFallback: true,
    
        // Inline mode is recommended when using Hot Module Replacement.
        inline: true,
        open: true,
        hot: true,
        overlay: {
          errors: true,
          warnings: true,
        },
        watchOptions: {
          aggregateTimeout: 300,
          poll: 1000,
        },
        // contentBase: path.resolve(__dirname, 'client', 'dist'),
        contentBase: '/',
        // match the output path
    
        publicPath: '/',
        // match the output `publicPath`
    
        port: 8080,
        proxy: {
          '/**': {
            target: 'http://localhost:3000',
            secure: false,
            changeOrigin: true,
          },
        },
      },
    

    open: true 会在命令执行时自动打开页面,contentBase: '/' 资源文件放置处,这里讲一下 proxy:
    因为我的项目有自己的后台,用nodejs写的,运行在3000端口,但是webpack-dev-server也有一个自己的运行后台,运行在 port: 8080 端口,那该怎么办?
    这时我们就需要进行代理proxy:
    host 默认是 localhost,对8080端口下的服务器进行请求,会自动把相同的请求转到3000下,比如我们请求 localhost:8080/api,代理以后会自动请求 localhost:3000/api,我这里是把所以请求都转到端口3000下,也可以只进行 /api 代理:

    '/api': {
        target: 'http://localhost:3000/api',
        secure: false,
        changeOrigin: true,
      },
    

    4
    关于 plugins:

    plugins: [
      // 除了自己写的代码,将其他的modules都bundle成一个vendor文件
      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        minChunks(module) {
          // 该配置假定你引入的 vendor 存在于 node_modules 目录中
          return module.context && module.context.indexOf('node_modules') !== -1;
        },
      }),
      // 生产manifest文件,用于在html模板中插入script
      new webpack.optimize.CommonsChunkPlugin({
        name: 'manifest',
        minChunks: Infinity,
      }),
      // 生成插入script后的 html 文件
      new HtmlWebpackPlugin({
        template: path.resolve(__dirname, 'server', 'static', 'index_template.html'),
        chunksSortMode: 'dependency',
        minify: {
          collapseWhitespace: true,
          removeComments: true,
        },
      }),
    
      // HMR
      new webpack.HotModuleReplacementPlugin(),
      // enable HMR globally
    
      new webpack.NamedModulesPlugin(),
      // prints more readable module names in the browser console on HMR updates
    ],
    

    说到生成环境的webpack配置,可以参考我的项目webpack.prod.js 文件。

    生产环境下我们就要兼顾很多方面,比如服务端发送到前端的文件要小,保证加载速度快;关于modules方面的代码我们很少会去修改,所以可以在前端进行缓存起来。

    1

    output: {
      path: path.resolve(__dirname, 'client', 'dist'),
      filename: '[name].[chunkhash].js',
      publicPath: '/',
    },
    

    这里对文件名进行了hash处理,浏览器会自动缓存js文件,如果收到的文件的文件名是一样的,浏览器可能不会进行自动更新,所以我们加上hash值,保证每一次更新以后的文件名不同,从而让浏览器再次请求资源。
    而那些modules代码基本是不会变的,所以保证它们的hash值不变,在浏览器处缓存起来。

    2
    plugins

    plugins: [
      // 将node_modules里的依赖整合成一个vendor
      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        minChunks(module) {
          // 该配置假定你引入的 vendor 存在于 node_modules 目录中
          return module.context && module.context.indexOf('node_modules') !== -1;
        },
      }),
    
      new webpack.optimize.CommonsChunkPlugin({
        name: 'manifest',
      }),
    
      // 根据manifest生成插入script后的html
      new HtmlWebpackPlugin({
        template: path.resolve(__dirname, 'server', 'static', 'index_template.html'),
        chunksSortMode: 'dependency',
        minify: {
          collapseWhitespace: true,
          removeComments: true,
        },
      }),
    
      // 将js文件压缩成gz
      new CompressionPlugin(),
    
      // 允许创建一个在编译时可以配置的全局常量
      new webpack.DefinePlugin({
        'process.env': {
          NODE_ENV: '"production"',
        },
      }),
    
      // 压缩
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false,
        },
        // sourceMap: true,
      }),
      new WebpackMd5Hash(),
      new webpack.NoEmitOnErrorsPlugin(),
    ],
    

    除了将文件进行 uglify 以外,这里还将文件进行gz压缩 new CompressionPlugin()
    在后端部分还要加上一些代码:

    // 获取js文件时选择gz压缩文件
    app.get('*.js', (req, res, next) => {
      req.url = req.url + '.gz';
      res.set('Content-Encoding', 'gzip');
      next();
    });
    

    以上。

    相关文章

      网友评论

        本文标题:关于webpack的react项目优化

        本文链接:https://www.haomeiwen.com/subject/trusfxtx.html