浅谈webpack 构建性能优化策略小结

背景

如今前端工程化的概念早已经深入人心,选择一款合适的编译和资源管理工具已经成为了所有前端工程中的标配,而在诸多的构建工具中,webpack以其丰富的功能和灵活的配置而深受业内吹捧,逐步取代了grunt和gulp成为大多数前端工程实践中的首选,React,Vue,Angular等诸多知名项目也都相继选用其作为官方构建工具,极受业内追捧。但是,随者工程开发的复杂程度和代码规模不断地增加,webpack暴露出来的各种性能问题也愈发明显,极大的影响着开发过程中的体验。

问题归纳

历经了多个web项目的实战检验,我们对webapck在构建中逐步暴露出来的性能问题归纳主要有如下几个方面:

  • 代码全量构建速度过慢,即使是很小的改动,也要等待长时间才能查看到更新与编译后的结果(引入HMR热更新后有明显改进);
  • 随着项目业务的复杂度增加,工程模块的体积也会急剧增大,构建后的模块通常要以M为单位计算;
  • 多个项目之间共用基础资源存在重复打包,基础库代码复用率不高;
  • node的单进程实现在耗cpu计算型loader中表现不佳;

针对以上的问题,我们来看看怎样利用webpack现有的一些机制和第三方扩展插件来逐个击破。

慢在何处

作为工程师,我们一直鼓励要理性思考,用数据和事实说话,“我觉得很慢”,“太卡了”,“太大了”之类的表述难免显得太笼统和太抽象,那么我们不妨从如下几个方面来着手进行分析:

  • 从项目结构着手,代码组织是否合理,依赖使用是否合理;
  • 从webpack自身提供的优化手段着手,看看哪些api未做优化配置;
  • 从webpack自身的不足着手,做有针对性的扩展优化,进一步提升效率;

在这里我们推荐使用一个wepback的可视化资源分析工具:webpack-bundle-analyzer,在webpack构建的时候会自动帮你计算出各个模块在你的项目工程中的依赖与分布情况,方便做更精确的资源依赖和引用的分析。

从上图中我们不难发现大多数的工程项目中,依赖库的体积永远是大头,通常体积可以占据整个工程项目的7-9成,而且在每次开发过程中也会重新读取和编译对应的依赖资源,这其实是很大的的资源开销浪费,而且对编译结果影响微乎其微,毕竟在实际业务开发中,我们很少会去主动修改第三方库中的源码,改进方案如下:

方案一、合理配置 CommonsChunkPlugin

webpack的资源入口通常是以entry为单元进行编译提取,那么当多entry共存的时候,CommonsChunkPlugin的作用就会发挥出来,对所有依赖的chunk进行公共部分的提取,但是在这里可能很多人会误认为抽取公共部分指的是能抽取某个代码片段,其实并非如此,它是以module为单位进行提取。

假设我们的页面中存在entry1,entry2,entry3三个入口,这些入口中可能都会引用如utils,loadash,fetch等这些通用模块,那么就可以考虑对这部分的共用部分机提取。通常提取方式有如下四种实现:

1、传入字符串参数,由chunkplugin自动计算提取

new webpack.optimize.CommonsChunkPlugin('common.js')

这种做法默认会把所有入口节点的公共代码提取出来, 生成一个common.js

2、有选择的提取公共代码

new webpack.optimize.CommonsChunkPlugin('common.js',['entry1','entry2']);

只提取entry1节点和entry2中的共用部分模块, 生成一个common.js

3、将entry下所有的模块的公共部分(可指定引用次数)提取到一个通用的chunk中

new webpack.optimize.CommonsChunkPlugin({
  name: 'vendors',
  minChunks: function (module, count) {
    return (
     module.resource &&
     /\.js$/.test(module.resource) &&
     module.resource.indexOf(
      path.join(__dirname, '../node_modules')
     ) === 0
    )
  }
});

提取所有node_modules中的模块至vendors中,也可以指定minChunks中的最小引用数;

4、抽取enry中的一些lib抽取到vendors中

entry = {
  vendors: ['fetch', 'loadash']
};
new webpack.optimize.CommonsChunkPlugin({
  name: "vendors",
  minChunks: Infinity
});

添加一个entry名叫为vendors,并把vendors设置为所需要的资源库,CommonsChunk会自动提取指定库至vendors中。

方案二、通过 externals 配置来提取常用库

在实际项目开发过程中,我们并不需要实时调试各种库的源码,这时候就可以考虑使用external选项了。

简单来说external就是把我们的依赖资源声明为一个外部依赖,然后通过script外链脚本引入。这也是我们早期页面开发中资源引入的一种翻版,只是通过配置后可以告知webapck遇到此类变量名时就可以不用解析和编译至模块的内部文件中,而改用从外部变量中读取,这样能极大的提升编译速度,同时也能更好的利用CDN来实现缓存。

external的配置相对比较简单,只需要完成如下三步:

1、在页面中加入需要引入的lib地址,如下:

<head>
<script src="https://cdn.bootcss.com/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/underscore.min.js"></script>
<script src="/static/common/react.min.js"></script>
<script src="/static/common/react-dom.js"></script>
<script src="/static/common/react-router.js"></script>
<script src="/static/common/immutable.js"></script>
</head>

2、在webapck.config.js中加入external配置项:

module.export = {
  externals: {
    'react-router': {
      amd: 'react-router',
      root: 'ReactRouter',
      commonjs: 'react-router',
      commonjs2: 'react-router'
    },
    react: {
      amd: 'react',
      root: 'React',
      commonjs: 'react',
      commonjs2: 'react'
    },
    'react-dom': {
      amd: 'react-dom',
      root: 'ReactDOM',
      commonjs: 'react-dom',
      commonjs2: 'react-dom'
    }
  }
}

这里要提到的一个细节是:此类文件在配置前,构建这些资源包时需要采用amd/commonjs/cmd相关的模块化进行兼容封装,即打包好的库已经是umd模式包装过的,如在node_modules/react-router中我们可以看到umd/ReactRouter.js之类的文件,只有这样webpack中的require和import * from 'xxxx'才能正确读到该类包的引用,在这类js的头部一般也能看到如下字样:

if (typeof exports === 'object' && typeof module === 'object') {
  module.exports = factory(require("react"));
} else if (typeof define === 'function' && define.amd) {
  define(["react"], factory);
} else if (typeof exports === 'object') {
  exports["ReactRouter"] = factory(require("react"));
} else {
  root["ReactRouter"] = factory(root["React"]);
}

3、非常重要的是一定要在output选项中加入如下一句话:

output: {
 libraryTarget: 'umd'
}

由于通过external提取过的js模块是不会被记录到webapck的chunk信息中,通过libraryTarget可告知我们构建出来的业务模块,当读到了externals中的key时,需要以umd的方式去获取资源名,否则会有出现找不到module的情况。

通过配置后,我们可以看到对应的资源信息已经可以在浏览器的source map中读到了。

对应的资源也可以直接由页面外链载入,有效地减小了资源包的体积。

方案三、利用 DllPlugin 和 DllReferencePlugin 预编译资源模块

我们的项目依赖中通常会引用大量的npm包,而这些包在正常的开发过程中并不会进行修改,但是在每一次构建过程中却需要反复的将其解析,如何来规避此类损耗呢?这两个插件就是干这个用的。

简单来说DllPlugin的作用是预先编译一些模块,而DllReferencePlugin则是把这些预先编译好的模块引用起来。这边需要注意的是DllPlugin必须要在DllReferencePlugin执行前先执行一次,dll这个概念应该也是借鉴了windows程序开发中的dll文件的设计理念。

相对于externals,dllPlugin有如下几点优势:

  1. dll预编译出来的模块可以作为静态资源链接库可被重复使用,尤其适合多个项目之间的资源共享,如同一个站点pc和手机版等;
  2. dll资源能有效地解决资源循环依赖的问题,部分依赖库如:react-addons-css-transition-group这种原先从react核心库中抽取的资源包,整个代码只有一句话:
module.exports = require('react/lib/ReactCSSTransitionGroup');

却因为重新指向了react/lib中,这也会导致在通过externals引入的资源只能识别react,寻址解析react/lib则会出现无法被正确索引的情况。

由于externals的配置项需要对每个依赖库进行逐个定制,所以每次增加一个组件都需要手动修改,略微繁琐,而通过dllPlugin则能完全通过配置读取,减少维护的成本;

1、配置dllPlugin对应资源表并编译文件

那么externals该如何使用呢,其实只需要增加一个配置文件:webpack.dll.config.js:

const webpack = require('webpack');
const path = require('path');
const isDebug = process.env.NODE_ENV === 'development';
const outputPath = isDebug ? path.join(__dirname, '../common/debug') : path.join(__dirname, '../common/dist');
const fileName = '[name].js';

// 资源依赖包,提前编译
const lib = [
 'react',
 'react-dom',
 'react-router',
 'history',
 'react-addons-pure-render-mixin',
 'react-addons-css-transition-group',
 'redux',
 'react-redux',
 'react-router-redux',
 'redux-actions',
 'redux-thunk',
 'immutable',
 'whatwg-fetch',
 'byted-people-react-select',
 'byted-people-reqwest'
];

const plugin = [
 new webpack.DllPlugin({
  /**
   * path
   * 定义 manifest 文件生成的位置
   * [name]的部分由entry的名字替换
   */
  path: path.join(outputPath, 'manifest.json'),
  /**
   * name
   * dll bundle 输出到那个全局变量上
   * 和 output.library 一样即可。
   */
  name: '[name]',
  context: __dirname
 }),
 new webpack.optimize.OccurenceOrderPlugin()
];

if (!isDebug) {
 plugin.push(
  new webpack.DefinePlugin({
   'process.env.NODE_ENV': JSON.stringify('production')
  }),
  new webpack.optimize.UglifyJsPlugin({
   mangle: {
    except: ['$', 'exports', 'require']
   },
   compress: { warnings: false },
   output: { comments: false }
  })
 )
}

module.exports = {
 devtool: '#source-map',
 entry: {
  lib: lib
 },
 output: {
  path: outputPath,
  filename: fileName,
  /**
   * output.library
   * 将会定义为 window.${output.library}
   * 在这次的例子中,将会定义为`window.vendor_library`
   */
  library: '[name]',
  libraryTarget: 'umd',
  umdNamedDefine: true
 },
 plugins: plugin
};

然后执行命令:

$ NODE_ENV=development webpack --config webpack.dll.lib.js --progress
$ NODE_ENV=production webpack --config webpack.dll.lib.js --progress 

即可分别编译出支持调试版和生产环境中lib静态资源库,在构建出来的文件中我们也可以看到会自动生成如下资源:

common
├── debug
│  ├── lib.js
│  ├── lib.js.map
│  └── manifest.json
└── dist
  ├── lib.js
  ├── lib.js.map
  └── manifest.json

文件说明:

  1. lib.js可以作为编译好的静态资源文件直接在页面中通过src链接引入,与externals的资源引入方式一样,生产与开发环境可以通过类似charles之类的代理转发工具来做路由替换;
  2. manifest.json中保存了webpack中的预编译信息,这样等于提前拿到了依赖库中的chunk信息,在实际开发过程中就无需要进行重复编译;

2、dllPlugin的静态资源引入

lib.js和manifest.json存在一一对应的关系,所以我们在调用的过程也许遵循这个原则,如当前处于开发阶段,对应我们可以引入common/debug文件夹下的lib.js和manifest.json,切换到生产环境的时候则需要引入common/dist下的资源进行对应操作,这里考虑到手动切换和维护的成本,我们推荐使用add-asset-html-webpack-plugin进行依赖资源的注入,可得到如下结果:

<head>
<script src="/static/common/lib.js"></script>
</head>

在webpack.config.js文件中增加如下代码:

const isDebug = (process.env.NODE_ENV === 'development');
const libPath = isDebug ? '../dll/lib/manifest.json' :
'../dll/dist/lib/manifest.json';

// 将mainfest.json添加到webpack的构建中

module.export = {
 plugins: [
    new webpack.DllReferencePlugin({
    context: __dirname,
    manifest: require(libPath),
   })
 ]
}

配置完成后我们能发现对应的资源包已经完成了纯业务模块的提取

多个工程之间如果需要使用共同的lib资源,也只需要引入对应的lib.js和manifest.js即可,plugin配置中也支持多个webpack.DllReferencePlugin同时引入使用,如下:

module.export = {
 plugins: [
   new webpack.DllReferencePlugin({
    context: __dirname,
    manifest: require(libPath),
   }),
   new webpack.DllReferencePlugin({
    context: __dirname,
    manifest: require(ChartsPath),
   })
 ]
}

方案四、使用 Happypack 加速你的代码构建

以上介绍均为针对webpack中的chunk计算和编译内容的优化与改进,对资源的实际体积改进上也较为明显,那么除此之外,我们能否针对资源的编译过程和速度优化上做些尝试呢?

众所周知,webpack中为了方便各种资源和类型的加载,设计了以loader加载器的形式读取资源,但是受限于node的编程模型影响,所有的loader虽然以async的形式来并发调用,但是还是运行在单个 node的进程以及在同一个事件循环中,这就直接导致了当我们需要同时读取多个loader文件资源时,比如babel-loader需要transform各种jsx,es6的资源文件。在这种同步计算同时需要大量耗费cpu运算的过程中,node的单进程模型就无优势了,那么happypack就针对解决此类问题而生。

开启happypack的线程池

happypack的处理思路是将原有的webpack对loader的执行过程从单一进程的形式扩展多进程模式,原本的流程保持不变,这样可以在不修改原有配置的基础上来完成对编译过程的优化,具体配置如下:

const HappyPack = require('happypack');
 const os = require('os')
 const HappyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length}); // 启动线程池});

module:{
  rules: [
   {
    test: /\.(js|jsx)$/,
    // use: ['babel-loader?cacheDirectory'],
    use: 'happypack/loader?id=jsx',
    exclude: /^node_modules$/
   }
  ]
 },
 plugins:[
  new HappyPack({
   id: 'jsx',
   cache: true,
   threadPool: HappyThreadPool,
   loaders: ['babel-loader']
  })
 ]

我们可以看到通过在loader中配置直接指向happypack提供的loader,对于文件实际匹配的处理 loader,则是通过配置在plugin属性来传递说明,这里happypack提供的loader与plugin的衔接匹配,则是通过id=happybabel来完成。配置完成后,laoder的工作模式就转变成了如下所示:

happypack在编译过程中除了利用多进程的模式加速编译,还同时开启了cache计算,能充分利用缓存读取构建文件,对构建的速度提升也是非常明显的,经过测试,最终的构建速度提升如下:

优化前:

优化后:

关于happyoack的更多介绍可以查看:

happypack

方案五、增强 uglifyPlugin

uglifyJS凭借基于node开发,压缩比例高,使用方便等诸多优点已经成为了js压缩工具中的首选,但是我们在webpack的构建中观察发现,当webpack build进度走到80%前后时,会发生很长一段时间的停滞,经测试对比发现这一过程正是uglfiyJS在对我们的output中的bunlde部分进行压缩耗时过长导致,针对这块我们可以使用webpack-uglify-parallel来提升压缩速度。

从插件源码中可以看到,webpack-uglify-parallel的是实现原理是采用了多核并行压缩的方式来提升我们的压缩速度。

plugin.nextWorker().send({
  input: input,
  inputSourceMap: inputSourceMap,
  file: file,
  options: options
});

plugin._queue_len++;

if (!plugin._queue_len) {
  callback();
}        

if (this.workers.length < this.maxWorkers) {
  var worker = fork(__dirname + '/lib/worker');
  worker.on('message', this.onWorkerMessage.bind(this));
  worker.on('error', this.onWorkerError.bind(this));
  this.workers.push(worker);
}

this._next_worker++;
return this.workers[this._next_worker % this.maxWorkers];

使用配置也非常简单,只需要将我们原来webpack中自带的uglifyPlugin配置:

new webpack.optimize.UglifyJsPlugin({
  exclude:/\.min\.js$/
  mangle:true,
  compress: { warnings: false },
  output: { comments: false }
})

修改成如下代码即可:

const os = require('os');
  const UglifyJsParallelPlugin = require('webpack-uglify-parallel');

  new UglifyJsParallelPlugin({
   workers: os.cpus().length,
   mangle: true,
   compressor: {
    warnings: false,
    drop_console: true,
    drop_debugger: true
    }
  })

目前webpack官方也维护了一个支持多核压缩的UglifyJs插件:uglifyjs-webpack-plugin,使用方式类似,优势在于完全兼容webpack.optimize.UglifyJsPlugin中的配置,可以通过uglifyOptions写入,因此也做为推荐使用,参考配置如下:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
 new UglifyJsPlugin({
  uglifyOptions: {
   ie8: false,
   ecma: 8,
   mangle: true,
   output: { comments: false },
   compress: { warnings: false }
  },
  sourceMap: false,
  cache: true,
  parallel: os.cpus().length * 2
 })

方案六、Tree-shaking & Scope Hoisting

wepback在2.X和3.X中从rolluo中借鉴了tree-shakingScope Hoisting,利用es6的module特性,利用AST对所有引用的模块和方法做了静态分析,从而能有效地剔除项目中的没有引用到的方法,并将相关方法调用归纳到了独立的webpack_module中,对打包构建的体积优化也较为明显,但是前提是所有的模块写法必须使用ES6 Module进行实现,具体配置参考如下:

 // .babelrc: 通过配置减少没有引用到的方法
 {
  "presets": [
   ["env", {
    "targets": {
     "browsers": ["last 2 versions", "safari >= 7"]
    }
   }],
   // https://www.zhihu.com/question/41922432
   ["es2015", {"modules": false}] // tree-shaking
  ]
 }

 // webpack.config: Scope Hoisting
 {
  plugins:[
   // https://zhuanlan.zhihu.com/p/27980441
   new webpack.optimize.ModuleConcatenationPlugin()
  ]
 }

适用场景

在实际的开发过程中,可灵活地选择适合自身业务场景的优化手段。

优化手段 开发环境 生产环境
CommonsChunk
externals  
DllPlugin
Happypack  
uglify-parallel  

工程演示demo

温馨提醒

本文中的所有例子已经重新优化,支持最新的webpack3特性,并附带有分享ppt地址,可以在线点击查看

小结

性能优化无小事,追求快没有止境,在前端工程日益庞大复杂的今天,针对实际项目,持续改进构建工具的性能,对项目开发效率的提升和工具深度理解都是极其有益的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解webpack性能优化——DLL

    Webpack性能优化的方式有很多种,本文之所以将 dll 单独讲解,是因为 dll 是一种最简单粗暴并且极其有效的优化方式. 在通常的打包过程中,你所引用的诸如:jquery.bootstrap.react.react-router.redux.antd.vue.vue-router.vuex 等等众多库也会被打包进 bundle 文件中.由于这些库的内容基本不会发生改变,每次打包加入它们无疑是一种巨大的性能浪费. Dll 的技术就是在第一次时将所有引入的库打包成一个 dll.js 的文件,将

  • webpack学习教程之前端性能优化总结

    前言 曾几何时,我们是如上图的方式引入JS资源的,相信现在很少遇见了.近年来Web前端开发领域朝着规范开发的方向演进.体现在以下两点: 1.MVC研发构架.多多益处(逻辑清晰,程序注重数据与表现分离,可读性强,利于规避和排查问题...) 2.构建工具层出不穷.多多益处(提升团队协作,以及工程运维,避免人工处理琐碎而重复的工作) 模块化开发 将前端性能优化理论落地,代码压缩,合并,缓存控制,提取公共代码等 其他的还包括比如你可以用ES 6 或CoffeeScript写源码,然后构建出浏览器支持的E

  • Webpack性能优化 DLL 用法详解

    前言 在用 Webpack 打包的时候,对于一些不经常更新的第三方库,比如 react,lodash,我们希望能和自己的代码分离开,Webpack 社区有两种方案 CommonsChunkPlugin DLLPlugin 对于 CommonsChunkPlugin,webpack 每次打包实际还是需要去处理这些第三方库,只是打包完之后,能把第三方库和我们自己的代码分开.而DLLPlugin 则是能把第三方代码完全分离开,即每次只打包项目自身的代码. 用法 要使用 DLLPlugin,需要额外新建

  • 浅谈webpack 构建性能优化策略小结

    背景 如今前端工程化的概念早已经深入人心,选择一款合适的编译和资源管理工具已经成为了所有前端工程中的标配,而在诸多的构建工具中,webpack以其丰富的功能和灵活的配置而深受业内吹捧,逐步取代了grunt和gulp成为大多数前端工程实践中的首选,React,Vue,Angular等诸多知名项目也都相继选用其作为官方构建工具,极受业内追捧.但是,随者工程开发的复杂程度和代码规模不断地增加,webpack暴露出来的各种性能问题也愈发明显,极大的影响着开发过程中的体验. 问题归纳 历经了多个web项目

  • 浅谈一下Nginx性能优化

    目录 Nginx 性能优化 1.Nginx运行工作进程数量 2.Nginx运行CPU亲和力 3.Nginx最大打开文件数 4.Nginx事件处理模型 5.开启高效传输模式 6.连接超时时间 7.fastcgi 调优 8.gzip 调优 9.expires 缓存调优 10.防盗链 11.内核参数优化 12.关于系统连接数的优化 Nginx 性能优化 1.Nginx运行工作进程数量 Nginx运行工作进程个数一般设置CPU的核心或者核心数x2.如果不了解cpu的核数,可以top命令之后按1看出来,也

  • 浅谈webpack构建工具配置和常用插件总结

    webpack构建工具已经火了好几年,也是当下狠火狠方便的构建工具,我们没有理由不去学习.既然选择webpack就要跟着时代走,我们要追随大牛的步伐,大牛等等我. 一.webpack基础 在根目录使用npm init 命令创建package.json,创建过程中一路回车. 本地安装webpack命令:npm install webpack webpack-cli --save-dev 安装成功后写入package.js的devDependencies中,可以通过 npm node_modules

  • 浅谈Vue 初始化性能优化

    前言 一般来说,你不需要太关心vue的运行时性能,它在运行时非常快,但付出的代价是初始化时相对较慢.在最近开发的一个Hybrid APP里,Android Webview初始化一个较重的vue页面竟然用了1200ms ~ 1400ms,这让我开始重视vue的初始化性能,并最终优化到200 ~ 300ms,这篇文章分享我的优化思路. 性能瓶颈在哪里? 先看一下常见的vue写法:在html里放一个app组件,app组件里又引用了其他的子组件,形成一棵以app为根节点的组件树. <body> <

  • 浅谈vue项目打包优化策略

    使用vue-cli部署生产包时,发现资源包很大,打包后的vendor.js达到了1.4M,这已经很大了,而且会影响到首屏加载.那么,怎么优化呢? 1.组件按需加载 这是首先可以优化的点.如果频繁使用了第三方组件/UI库,如我的项目中经常同时使用了 element-ui, mint-ui,echarts等组件库,如果全部引入,项目体积非常大,这时可以按需引入组件. 示例如下: 1.1 element-ui 首先,安装 babel-plugin-component: npm install babe

  • 浅谈vue加载优化策略

    vue.js是一个比较流行的前端框架,与react.js.angular.js相比来说,vue.js入手曲线更加流畅,不管掌握多少都可以快速上手.但是单页面应用也都有其弊病,有时候首屏加载慢的让人捏舌.今天我们以vue cli3.x来说一说如何行之有效的缓解此问题! 方法一 路由懒加载 首屏加载慢的原因无非就是单页面应用需要加载完整个路由表上的页面,而路由懒加载就是来解决这个问题的.如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了.下面这个

  • 浅谈React + Webpack 构建打包优化

    本文介绍了React + Webpack 构建打包优化,分享给大家,具体如下: 使用 babel-react-optimize对 React 代码进行优化 检查没有使用的库,去除 import 引用 按需打包所用的类库,比如 lodash . echart 等 lodash 可以采用babel-plugin-lodash进行优化. 需要注意的是 在 babel-react-optimize 中使用了 babel-plugin-transform-react-remove-prop-types 这

  • 浅谈MySQL大表优化方案

    背景 阿里云RDS FOR MySQL(MySQL5.7版本)数据库业务表每月新增数据量超过千万,随着数据量持续增加,我们业务出现大表慢查询,在业务高峰期主业务表的慢查询需要几十秒严重影响业务 方案概述 一.数据库设计及索引优化 MySQL数据库本身高度灵活,造成性能不足,严重依赖开发人员的表设计能力以及索引优化能力,在这里给几点优化建议 时间类型转化为时间戳格式,用int类型储存,建索引增加查询效率 建议字段定义not null,null值很难查询优化且占用额外的索引空间 使用TINYINT类

  • 浅谈webpack下的AOP式无侵入注入

    说起来, 面向切面编程(AOP)自从诞生之日起,一直都是计算机科学领域十分热门的话题,但是很奇怪的是,在前端圈子里,探讨AOP的文章似乎并不是多,而且多数拘泥在给出理论,然后实现个片段的定式)难免陷入了形而上学的尴尬境地,本文列举了两个生产环境的实际例子论述webpack和AOP预编译处理的结合,意在抛砖引玉.当然,笔者能力有限,如果有觉得不妥之处,还请大家积极的反馈出来, 共同进步哈. 重要的概念 AOP: 面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. Joi

  • 浅谈webpack打包之后的文件过大的解决方法

    以前一直使用 create-react-app 这个脚手架进行 react 开发,后面因为一些自定义的配置,转而使用 webpack 搭建一套自己的脚手架.但是在使用 webpack 打包之后发现,纳尼?怎么文件这么大??? 于是研究了一下如何处理 webpack 打包之后文件太大的情况,简单记录下来. 首先配置全局变量 首先,通过指定环境,告诉 webpack 我们当前处于 production 环境中,要按照 production 的方式去打包. //指定环境,将process.env.NO

随机推荐