关于webpack的react项目优化

这几天有空给自己写的一个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(
    
      
    ,
    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项目优化)