webpack3终极配置及其优化(react)

Posted 小章鱼哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack3终极配置及其优化(react)相关的知识,希望对你有一定的参考价值。

本文主要研究webpack3版本的react项目配置。

webpack的原理

在普通开发者看来,webpack就是一个黑盒。


由一个或多个Entry(输入)传入,最后输出一个或多个Output(输出)

webpack的内部具体是如何处理的呢?

webpack几大概念

  • Entry: 输入。webpack从此处开始执行构建。
  • Output:输出。webpack最终处理输出的文件。
  • Plugin: 插件。webpack处理时抛出事件,插件接受事件处理额外的逻辑。
  • Loader:模块转换器。内容转换。
  • Module:模块。一个文件就是一个模块。
  • Chunk:块。一个块有一个或多个模块组成。

webpack执行流程

  1. 首先webpack会把Entry(输入)文件当作一个Module(模块)
  2. (使用Loaders,稍后会讲)翻译Module文件,并识别出Module文件的所有依赖文件。
  3. 然后对其依赖的文件再进行步骤2。
  4. 所有Module识别完之后,根据每个模块和Entry的对应关系,组装成一个或多个Chunk,并输出到输出列表。
  5. 根据Output的相关配置,输出到文件里。
  6. 这个过程中,webpack会在操作过程中广播特定事件,PLugin(插件)会在自己感兴趣的事件后,执行特定逻辑。

webpack如何解析文件与文件之间的联系?

对于模块与模之间的联系,开发者通常会
- 使用script标签引入
- 通过commonjs(commonjs1,commonjs2)引入
- 通过AMD(require.js)引入
- 通过es6定义的模块引入方式引入

除了第一种方式,webpack都可以识别,作为文件依赖的标志,我们可以通过config配置,去支持或禁用哪一种引入方式。

为什么要使用loader?

假设我们写了这么一行代码:

import style from './index.css'

不好意思,webpack解析不了。

webpack原生不能解析css文件,目前webpack只能原生解析js文件,需要Loader转换并插入到js文件。还有图片文件等等都需要Loader支持。(具体配置见后文)

为什么要使用plugin?

Plugin可以大大扩展webpack的功能,哈哈。(具体配置见后文)

webpack的基础搭建

基本配置

只要有输入,输出,webpack就能跑起来了。

// commonJS语法
const path = require(path);
const config = 
    entry: 'app.js',
    output: 
        filename: '[name].js',
        path: path.resolve(__dirname, '')
    



module.exports = config;

如果我们定义了多个入口文件,我们就会输出与入口文件数量对应的多个包。

Scope Hoisting

生成的output文件本身是一个自执行函数,在webpack3版本,对于导出的文件还会进行Scope Hoisting

打个比方。

// a.js
import b from 'b.js'
document.write("hello" + b);
// b.js

export default 'world';

假设我们的a.js是webpack的入口文件,a.js文件依赖b.js文件。webpack3打包之后会是这样:

// bundle.js

!function()
....

([function(e, t, r) 
    "use strict";
    r.r(t);
    document.write("hello world")
])

b文件的作用域被提升了(webpack2就不会如此)。这会大大减小最后打包之后的体积。并且打包之后作用域变少,减小内存开销。

注: 只有es6代码可以被Scope Hoisting,而且,如果一个文件被多个文件依赖,就不会使用Scope Hoisting

所以我们如果对于webpack打包的速度,打包后的体积不满意,可以试着更新webpack的版本哦。

webpack针对react-route的按需加载

如果您的项目使用了react-route,webpack会对您的应用进行打包的时候,根据您的路由,打包成多个chunk输出。

比如: 我配置的路由有upload和plan两个路由。webpack会帮您打包成两个输出文件。实现按需加载。

环境配置

生产环境,发布环境代码要不同的嘛。
所以会做环境的区分。

// webpack.config.js
const envDevelopment = project.env === 'development'
const envProduction = project.env === 'production'
// package.json

"dev": "cross-env NODE_ENV=development webpack -p --config webpack.config.js",
"prod": "cross-env NODE_ENV=production webpack -p --config webpack.config.js",

loaders

scss loaders

module.exports =  module: 
rules: [

     test: /\\.scss/ ,  // 使用正则表示,匹配文件名
     use: [’style-loader’,’css-loader’,’sass-loader’]
   ]
 

对于use,从后向前解析。先使用sass-loader,再使用css-loader解析,最后使用style-loader解析。

sass-loader会将sass文件转换成css文件。
css-loader会解析css文件的依赖关系(@import),构建关于css的依赖。
style-loader会将css注入js,动态向DOM注入样式。

可以使用ExtractTextPlugin插件将css单独打包而不是注入js文件中。

postcss

postcss是一个css处理平台。它是一个css编译器。平台有一系列css处理插件,比如autoprefixer插件可以自动为css添加前缀-webkit- , --mos-

关于postcss的配置,可以直接在webpack的配置里写,也可以单独一个postcss.config.js文件写。

// postcss.config.js
module.exports = 
    options: 
        plugins: [
            require('autoprefixer')(
                browsers: [
                    'ie >= 9',
                    'Edge >= 12'
                ]
            )
        ]
    
;

js loaders

vue有专门的vue-loader
react,es6代码可以使用babel转换。
typescript代码使用awesome-typescript-loader

babel

类似postcss,babel是一个js编译器。它可以帮我们将代码转译成我们需要的js代码。

我们可以在.babelrc里配置。


    "presets": [
        "es2015",
        "react",
        "stage-2"
    ],
    "plugins": [
        "transform-runtime",
        "add-module-exports",
        "transform-class-properties",
        [
            "import",
            
              "libraryName": "antd",
              "style": true
            
        ]
    ]

plugins指定我们需要哪些插件。其中transform-runtime是必须要装的,为了保证babel正常运行。
presets告诉babel待转换的js代码都使用了哪些特性。
stage-2是还未纳入ECMAScript标准的草案。

需要注意的是,我们在webpack的配置时

module.exports =  
    module: 
        rules: [
            test: /\\.js$/,
            use: ['babel-loader'],
        ]
    
    //输出 source-map 以方便直接调试 ES6 源码 
    devtool: 'source-map'

图片loaders


                test: /\\.(png|jpe?g|gif|svg|cur)?$/,
                exclude: /node_modules/,
                use: [
                    loader: 'url-loader',
                    options: 
                        limit : 2560,
                        name: '[path][name].[ext]?v=[hash]'
                    
                ]
            ,

url-loader可以将小于limit大小的图片转换成base64,嵌入到html文件中,减少网络请求。

精灵图

还记得我们在介绍sass loader的时候,解析到css-loader之前,可以加入sprite-loader。它可以将图片组成雪碧图,减少网络请求。

module.exports =  module: 
rules: [

     test: /\\.scss/ ,  // 使用正则表示,匹配文件名
     use: [’style-loader’,’css-loader’,’sass-loader’]
   ]
 

plugins

UglifyJsPlugin

压缩代码插件,在prod打包模式下,需要将代码压缩。
webpack有一个秒杀其他打包工具的特性: tree-shaking(虽然它也是借鉴来的)。tree-shaking是webpack自带的功能,它可以检查无用代码,需要配合UglifyJsPlugin在代码压缩的时候,剔除无用代码。

所以在dev模式,我的项目3mb,但是在prod模式,我的代码在压缩之后,只有200kb。(看来我引入了大的包,而且利用率不高呀)

webpack-parallel-uglify-plugin

随着项目越来越庞大,如果觉得UglifyJsPlugin比较慢 ,可以使用webpack-parallel-uglify-plugin,它可以使用多进程,并行压缩代码,速度显著提高。

CommonsChunkPlugin

如果有很多个文件都引入了一个文件,我们可以使用CommonsChunkPlugin将重复的文件打包到一起,防止重复打包。

还有很多插件,在webpack官网上面可以找到。

热替换与自动刷新

我们希望我们的构建工具可以实时监听代码的变化,便于调试。

这里有webpack体系下的几种办法:

插件HotModuleReplacementPlugin

这家伙只能监听变化,不能刷新浏览器。

开启watch模式

// webpack.config.js
export default = 
    watch: true,
    module.export =  
        watchOptions : 
            //不监听的 node modules 目录下的文件 
            ignored : /node_modules/,
        
    

不监听的 node modules 目录下的文件 ,会大大优化webpack速度。

// 或 package.json
'dev': "webpack --watch"

这家伙只能监听变化,不能刷新浏览器。

webpack-dev-server

这个插件会自动开启webpack的watch模式,而且会自动刷新浏览器。

webpack的性能优化

happypack

多进程并行执行Loader

缩小范围

Loaders 和Plugins可以配置includesexcludes,可以缩小执行范围。
比如babel转换。

  module: 
        rules: [
            
                test: /\\.(js|jsx)?$/,
                exclude: /node_modules/,  // 去除node modules文件夹的文件
                use: 'happypack/loader?id=jsx'  // 这里使用了happypack
            ]
 

DllPlugin

动态链接库。
提前打包一些文件,在真实打包的时候,把他们链接进来,不需打包,直接引入。

etc

其他优化方式前面提过

  1. tree-shaking和压缩代码,使代码体积变小
  2. CommonsChunkPlugin单独打包重复使用的文件
  3. 按需加载

webpack相较于其他构建工具的优势与劣势

优势:

  1. TreeShaking(lodash,moment库blabla)
  2. 热替换功能,以提高开发效率;
  3. 支持SourceMap,以方便调试;
  4. 区分打包环境

劣势: 有点慢

以上是关于webpack3终极配置及其优化(react)的主要内容,如果未能解决你的问题,请参考以下文章

从源码中来,到业务中去,React性能优化终极指南

手把手教你用webpack3搭建react项目(开发环境和生产环境)

(webpack系列二)webpack打包优化探索

(webpack系列二)webpack打包优化探索

webpack3+react构建应用

(源码开放) React + webpack3 多页面应用 及 常见问题解答