2018年度总结

305 阅读7分钟

回首相望于时光,毕业至今已三年有余。曾懵懂、莽撞,拘泥于小小空间,以此足矣。然其自强不息,不满于此,从事前端工作。而后工于技术。现追随潮流,做年度总结文章一篇,以此记录...

2018 年前,我还在公司做着 jQuery 与 PHP 的项目。而后公司领导层做了关于技术选型的讨论,但并没有做技术选型的定论,网上搜索许久,每种技术各有说辞,无意间看到一篇关于 React 的文章,适合我们的项目,感觉挺有挑战性的,于是我决心在业余之时学习先学习下 React(万一用上了呢)。 我花了两个月的时间学会了 React 技术的使用,包括其中的 API、状态管理、路由等。恰逢学习之际,公司技术选型中有一个小项目是想先用 React 试用下。于是给了我一个练手的机会,让我基本上掌握了 React 的使用,但对于 redux 状态管理并不是很理解,只知道他的作用于用法,直到项目结束,我依旧处于半梦半醒的状态。 有人说慢慢学习、多加练习,终究会恍然大悟... 可是文章到这,你以为接下来我要讲述自己是如何认真学习 React 的么?

.........

并没有,一个 Vue 项目来了... 都说 Vue 比较容易上手,于是我花了十天的时间通读了 Vue 的 API,并搭建了 Vue 项目,其中包括 Sass 管理 css,Vuex 状态管理,webpack 打包等等的配置。果然,跟 React 相比,是容易了许多。我以为自己可以沉浸在这小小的成就中,可以空余些时间多多学习其他没用到的 API,或者学习下 webpack 的相关内容。然而,我以为的以为终究不是我以为。

项目结束后,偶尔参与下这个项目的需求。由于某种原因我又转战了 React 项目。经过 Vuex 的学习使用,对于状态管理方面的东西理解了很多,在实际使用中,也简单了许多。

2018 年是我辞职转战团队的一年,我于 8 月份来到了现在的这个团队。说实话我很喜欢现在团队的氛围,90 后占据了主要的部分,青春洋溢的色彩。进入公司后,依旧做着 React 项目,对公司的一个 React15.0 + Webpack1.12.0 + Ant.design 的老项目进行优化,由于项目的代码量极大,导致打包后的10M以上,所以我们采取了按需加载的方案,用 require.ensure 来拆分项目代码,结果代码量没降反而增加很多。于是使用了 webpack 插件 webpack-bundle-analyzer 进行了分析。

webpack-bundle-analyzer

使用 webpack-bundle-analyzer 插件分析项目分析,优化代码,提升性能

  • 安装依赖包:

    npm install webpack-bundle-analyzer --save-dev

  • webpack 配置:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
        //  可以是`server`,`static`或`disabled`。
        //  在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。
        //  在“静态”模式下,会生成带有报告的单个HTML文件。
        //  在`disabled`模式下,你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。
        analyzerMode: 'server',
        //  将在“服务器”模式下使用的主机启动HTTP服务器。
        analyzerHost: '127.0.0.1',
        //  将在“服务器”模式下使用的端口启动HTTP服务器。
        analyzerPort: 8866, 
        //  路径捆绑,将在`static`模式下生成的报告文件。
        //  相对于捆绑输出目录。
        reportFilename: 'report.html',
        //  模块大小默认显示在报告中。
        //  应该是`stat`,`parsed`或者`gzip`中的一个。
        //  有关更多信息,请参见“定义”一节。
        defaultSizes: 'parsed',
        //  在默认浏览器中自动打开报告
        openAnalyzer: true,
        //  如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
        generateStatsFile: false, 
        //  如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
        //  相对于捆绑输出目录。
        statsFilename: 'stats.json',
        //  stats.toJson()方法的选项。
        //  例如,您可以使用`source:false`选项排除统计文件中模块的来源。
        //  在这里查看更多选项:https:  //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
        statsOptions: null,
        logLevel: 'info'
    })
  ]
}

commons-chunk-plugin

经过分析,发现拆分后得每个 js 文件中都包含了重复的代码,比如 antd 之类的插件。,考虑将公共的代码提取出来,减少总体打包之后的代码,并且提取的公共代码也比较稳定,于是引入了 webpack 官方提供的 CommonsChunkPlugin 插件(但是在 webpack v4 中已经被移除,使用了 SplitChunksPlugin 插件)。 webpack 网站做了CommonsChunkPlugin 插件的

  • 相关说明:

    CommonsChunkPlugin 插件,是一个可选的用于建立一个独立文件(又称作chunk)的功能,这个文件包括多个入口 chunk 的公共模块。它的作用是通过将公共模块拆出来,最终合成的文件能够在最开始的时候加载一次,便存到缓存中供后续使用。这个带来页面速度上的提升,因为浏览器会迅速将公共的代码从缓存中取出来,而不是每次访问一个新页面时,再去加载一个更大的文件。。

  • 安装依赖包

    npm install commons-chunk-plugin --save

  • 使用及配置说明:

new webpack.optimize.CommonsChunkPlugin({
  name: string, // or
  names: string[],
  // 这是 common chunk 的名称。已经存在的 chunk 可以通过传入一个已存在的 chunk 名称而被选择。
  // 如果一个字符串数组被传入,这相当于插件针对每个 chunk 名被多次调用
  // 如果该选项被忽略,同时 `options.async` 或者 `options.children` 被设置,所有的 chunk 都会被使用,
  // 否则 `options.filename` 会用于作为 chunk 名。
  // When using `options.async` to create common chunks from other async chunks you must specify an entry-point
  // chunk name here instead of omitting the `option.name`.

  filename: string,
  // common chunk 的文件名模板。可以包含与 `output.filename` 相同的占位符。
  // 如果被忽略,原本的文件名不会被修改(通常是 `output.filename` 或者 `output.chunkFilename`)。
  // This option is not permitted if you're using `options.async` as well, see below for more details.

  minChunks: number|Infinity|function(module, count) => boolean,
  // 在传入  公共chunk(commons chunk) 之前所需要包含的最少数量的 chunks 。
  // 数量必须大于等于2,或者少于等于 chunks的数量
  // 传入 `Infinity` 会马上生成 公共chunk,但里面没有模块。
  // 你可以传入一个 `function` ,以添加定制的逻辑(默认是 chunk 的数量)

  chunks: string[],
  // 通过 chunk name 去选择 chunks 的来源。chunk 必须是  公共chunk 的子模块。
  // 如果被忽略,所有的,所有的 入口chunk (entry chunk) 都会被选择。

  children: boolean, // 如果设置为 `true`,所有公共 chunk 的子模块都会被选择

  deepChildren: boolean,
  // 如果设置为 `true`,所有公共 chunk 的后代模块都会被选择

  async: boolean|string,
  // 如果设置为 `true`,一个异步的  公共chunk 会作为 `options.name` 的子模块,和 `options.chunks` 的兄弟模块被创建。
  // 它会与 `options.chunks` 并行被加载。
  // Instead of using `option.filename`, it is possible to change the name of the output file by providing
  // the desired string here instead of `true`.

  minSize: number,
  // 在 公共chunk 被创建立之前,所有 公共模块 (common module) 的最少大小。
});

通过 require.ensure 等方式拆分代码,需要借助 children 来提取公共模块,代码会拼接到 entry chunk 上。如果 async 为 true 的时候,会重新创建一个文件来放置。

entry: {
  app: './entry'
},

plugins: [
    new webpack.optimize.CommonsChunkPlugin({
        children: true,
        async: 'async-common', // 定义 chunk 名字
        minChunks: 2,
    })
]

extract-text-webpack-plugin

使用了 webpack 插件 extract-text-webpack-plugin(但是在 webpack v4中将不再使用,替换成mini-css-extract-plugin 插件),将 css 样式进行了抽离,需要将 style-loader 删掉,否则会导致模块构建失败,参考 github issues

  • 安装依赖包

    npm install extract-text-webpack-plugin --save

  • 使用及配置:

const ExtractTextPlugin = require('extract-text-webpack-plugin');
plugins: [  
    new ExtractTextPlugin('[name].css')
].
module:{
    loaders: [{
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('css-loader')
    }, {
        test: /\.less/,
        loader: ExtractTextPlugin.extract('css-loader!less-loader?')
    }]
}
  • children + async

使用 children + async 的方式进行打包(需要添加参数 allChunks),最后只有 8.7 M

plugins: [  
    new ExtractTextPlugin('[name].css',{
        allChunks : true
    }),
    new webpack.optimize.CommonsChunkPlugin({
        children: true,
        async: 'async-common',
        minChunks: 3,
    })
]

更多文章看这里哦!!!