webpack 打包编译优化之路

一、摘要

从最初的html css js 混合编程,到分离编程。再到用上各种框架 react vue angular , 伴随着框架和模块化的概念铺开,打包编译工具渐渐浮出水面。从2013年开始使用打包编译工具,其也经历了多个更新换代,从最初的grunt -> gulp -> webpack , 还有一些自成体系的,例如 fis , 还有一些比较小众的 rollup , browserify 等。我这里主要分享的是基于 typescript + scss 的webpack3打包编译。

二、webpack3配置

2.1 关键配置

entry

打包编译入口,可以单入口也可以多入口

entry : 'xxx/index.tsx',   // 单入口
entry : ['xxx/index.tsx', 'yyy/index.tsx'],   // 多入口
entry : {          // 多入口, 并指定编译后的名字
  a: 'xxx/index.tsx',
  b: 'yyy/index.tsx',
},   // 多入口

output

path 指定输出路径
filename 输出的文件名字,可增加 hash 后缀
publicPath 指定了你在浏览器中用什么地址来引用你的静态文件,它会包括你的图片、脚本以及样式加载的地址,一般用于线上发布以及CDN部署的时候使用。

{
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: "[name].bundle.[hash:8].js",
    publicPath: "http://localhost:3000/build/"
  },
}

resolve

extensions 自动加上文件扩展名,在 import 时 可省略, 比如 import './a.tsx' 可简写成 import './a'
alias 设置别名,一些常用的库设置别名,可以有效减少import的路径。推荐一个 很好用的插件 alias-resolve-loader 可以把node_modules 依赖的alias 也一并替换。

resolve: {
  alias: {
    jquery: 'xxxx/xxxx/jqueryjs'
  }
}

module

根据你项目使用的语言选择解析loader , 我这里有两种文件 tsx scss ,就分别指定了两种文件的解析loader

url-loader

超出 8192 大小的 img 用图片形式,其他采用 base64 码形式打包到js中调用

module: {
  loaders:[
    { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192&publicPath=./dist/'},
  ]
}

plugins

webpack 最强大的就是plugins 生态了,基本你想要的功能都能有现成 plugin 插件直接使用。我们一般常见的插件有

  • webpack.optimize.CommonsChunkPlugin 抽离不常改变的公共组件, 线上环境使用
  • webpack.optimize.UglifyJsPlugin 丑化 js , 线上环境使用
  • ExtractTextPlugin css js 拆分,webpack 默认是把css js 全部打包到一个文件,这样通常会面临加载一个庞大的bundle.js 文件,有这个插件就可以实现 css js 拆分,html 并行加载css js
  • BundleAnalyzerPlugin 分析打包文件大小,可以进一步做文件抽离

devtool

可以把错误映射到真实代码中,方便排查错误,生产环境不加

2.2 真实案例

真实项目中,一般线下调试和线上是两个版本 webpack 配置

线下

线下就做最简单的tsx scss 编译,打包成一个大文件

const path = require('path'); // 导入路径包
const webpack = require('webpack');

let config = {
  context: __dirname,
  devtool: "source-map",
  entry: {
    assetManage: "./src/xxx/index.tsx",
  },

  output: {
    path: path.resolve(__dirname, 'build'),
    filename: "[name].bundle.js",
    publicPath: "http://localhost:3000/build/"
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js", ".jsx", ".json"]
  },
  // 使用loader模块
  module: {
    loaders: [
      {test: /\.scss$/, loader: "style-loader!css-loader!sass-loader"},
      {test: /\.tsx?$/, loader: ['react-hot-loader', "ts-loader"]}
    ]
  },
  plugins: [],
};

module.exports = config;

线上

线上需要生成文件大小,尽量减少页面加载时间

const path = require('path'); // 导入路径包
const webpack = require('webpack');

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const CompressionPlugin = require("compression-webpack-plugin");

let config = {
  context: __dirname,
  entry: {
    service: "./src/xxx/index.tsx",
    vendor: ['react', 'react-dom'],
  },
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: "[name].bundle.js",
    publicPath: "http://localhost:3000/build/"
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js", ".jsx", ".json"]
  },
  module: {
    loaders: [
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: [{
            loader: "css-loader",
            options: {
              minimize: true
            }
          }, "sass-loader"]
        })
      },
      {test: /\.tsx?$/, loader: ['react-hot-loader', "ts-loader"]}
    ]
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor'
    }),
    new webpack.optimize.UglifyJsPlugin(),
    new ExtractTextPlugin({
      filename: 'css/[name].css',
      allChunks: true
    }),
    new BundleAnalyzerPlugin()
  ],
};

module.exports = config;

三、优化手段

  1. 抽离公共组件 vendor , 拆分基础组件 与 业务逻辑代码

  2. 拆分css至单独文件并压缩

  3. 去除 devtool

  4. 增加 BundleAnalyzerPlugin 分析

四、其他

webpack 的替代方案?

happypack

rollup

posted @ 2017-10-18 10:58  空城夕  阅读(451)  评论(0编辑  收藏  举报