Git Product home page Git Product logo

maxpsc.github.io's Introduction

maxpsc.github.io

个人博客,记录、分享所见所学。
简单记录到issues, 累计一定数量会整理到hexo里。

maxpsc.github.io's People

Contributors

maxpsc avatar

Watchers

 avatar  avatar

maxpsc.github.io's Issues

webpack进阶之优化打包策略

webpack进阶

目录

  1. 如何优化打包策略
  2. 核心概念详解(loader, plugin
  3. 如何写一个plugin

正文

优化打包策略

可通过webpack-bundle-analyzer查看输出文件的大小、包含关系等属性,以此为依据分析打包策略。

打包时间长?

  1. 第三方库体积庞大且重复依赖
  2. node单线程,同一时间只能存在一个打包任务
  3. uglifyJs本身比较耗时

具体优化过程(分别对应以上问题):

  1. 设置external, 将复用次数较多且体积庞大的第三方库提取出来,在index.html统一以script引入;
    ⇣⇣⇣⇣⇣⇣⇣⇣⇣⇣⇣⇣⇣⇣⇣⇣⇣⇣
    多个第三方库则借鉴Windows中的dll文件理念(Dynamic Link Library, 动态链接库文件),事先将其抽离并整合成一个dll文件,若依赖不变,则只需打包一次dll文件,以后只引入即可,可理解为将多个external整合为一个。
    配置文件改动:
module.exports = {
    // ...
    // webpack-dll相关配置, 区分开发和生产环境
    // 当entry为一个对象时,每一个key为一个dll
    // 例如:{entry: { 'vendor1': ['xxx', 'xxx1'], 'vendor2': ['xxx2', 'xxx3'] }}
    dll: {
        dev: {
        enable: true,
        entry: [
            'highcharts',
            'd3',
            'openlayers',
            'lodash',
            'vue',
            'vue-router',
            'vuex'
        ],
        outPath: resolve('static/dll')
        },
        prod: {
        enable: true,
        entry: [
            'highcharts',
            'd3',
            'openlayers',
            'lodash',
            'vue',
            'vue-router',
            'vuex'
        ],
        outPath: resolve('dist/static/dll')
        }
    }
    // ...
};
  1. 使用happypack进行多线程构建

HappyPack makes webpack builds faster by allowing you to transform multiple files in parallel.

调用方法:

var HappyPack = require('happypack');
var happyThreadPool = HappyPack.ThreadPool({ size: 4 }); //分配的线程数
module.exports = {
// ...
plugins: [
    // ...
    new HappyPack({
        id: 'vue',
        threadPool: happyThreadPool,
        loaders: [ 'vue-loader' ]
    }),
    new HappyPack({
        id: 'js',
        threadPool: happyThreadPool,
        loaders: [ 'babel-loader' ]
    })
    ]
};
  1. 使用webpack-parallel-uglify-plugin多线程并行压缩

This plugin runs uglify in parallel with one thread for each of your available cpus.
This can lead to significantly reduced build times as minification is very CPU intensive.

调用方法:

var UglifyJsParallelPlugin = require('webpack-uglify-parallel');
module.exports = {
// ...
plugins: [
    // ...
    new UglifyJsParallelPlugin({
      workers: os.cpus().length,
      compress: {
        warnings: false
      },
      sourceMap: true
    })
    ]
};

优化前打包时间:
before
优化后打包时间:
after

webpack核心概念

loader

webpack通过loader对文件进行预处理,是其打包静态资源的核心功能。
在webpack配置文件中声明如下:

// @qnpm/ssa-scripts/bin/webpack.base.conf.js
// ...
var webpackConf = {
    // ...
    module: {
        rules: [
        {
            test: /\.vue$/,
            loader: 'vue-loader',
            options: vueLoaderConfig
        },
        {
            test: /\.js$/,
            loader: 'babel-loader',
            include: [ utils.resolve('src'), utils.resolve('test') ]
        },
        {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            loader: 'url-loader',
            options: {
                limit: 10000,
                name: utils.assetsPath('img/[name].[hash:7].[ext]')
            }
        },
    },
    // ...

常用loader:

  • babel-loader
    下一代Javscript编译器在webpack上的实现,将ES3(5)编译为ES2015+

  • style-loader, css-loader, sass-loader
    css-loader解释css(scss, less)文件中@import等语句,引入对应文件,此过程还可使用sass-loader或less-loader编译为css
    style-loader作用是将上述导出的内容以style形式添加到DOM中
    由于webpack loader执行顺序从右至左,所以一般配置会将style-loader放在css-loader左边

  • file-loader, url-loader
    file-loader功能单一,将文件传输到指定文件夹并返回相对URL;
    url-loader在file-loader的基础上还能对文件大小做限制,小于limit时,返回base64编码的DataURL

  • vue-loader
    解析.vue文件,提取每个语言块,通过其它对应loader处理。

    • template
      html-loader, 内容提取为字符串,编译后作为Vue组件的template内容
    • script
      js-loader, 可理解为webpack正常打包的js模块,自动检测并应用babel-loader
    • style
      css-loader, 默认用style-loader提取内容

plugin

插件一般为webpack打包提供辅助功能,ssa-script用到以下几个:
注:驼峰命名表示webpack内置插件, 连接符命名表示第三方插件,后有*说明根据配置是可选插件

  • 开发环境

    • HotModuleReplacementPlugin
      配合使用简单的webpack-dev-server或利用webpack-hot-middleware配置webpack实例实现模块热替换HMR

    • NoEmitOnErrorsPlugin
      编译时出现错误,用此插件跳过输出阶段,确保输出资源不会包含错误

    • friendly-errors-webpack-plugin
      编译中出现错误,格式化错误信息并展示

  • 生产环境

    • webpack-uglify-parallel
      多线程压缩、混淆输出文件

    • extract-text-webpack-plugin
      将所有从入口引入的css文件从JS bundle分离并提取到一个独立的css文件

    • optimize-css-assets-webpack-plugin
      优化、压缩css内容,并解决extract-text-webpack-plugin导致的代码重复的问题

    • optmize.CommonsChunkPlugin
      将不同文件引用的相同资源拆出来,作为公共模块在最开始的时候加载一次

    • copy-webpack-plugin
      在webpack运行周期内进行的拷贝文件操作

    • compression-webpack-plugin *
      gzip编码静态资源,不过一般在服务端进行编码,使用较少

    • webpack-bundle-analyzer *
      打包后根据stats.json以可视化方式展示输出文件的大小、包含关系等属性

  • 共同插件

    • DefinePlugin
      创建在编译时可配置的全局变量,只要勇于区分开发和生产环境

    • html-webpack-plugin
      自定义生成HTML文件,其中可引入打包中的相关变量和资源

    • html-webpack-include-assets-plugin
      html-webpack-plugin的功能增强版,可在assets中进行编程控制

    • DllReferencePlugin *
      第三方依赖预编译,用于打包优化

    • stylelint-webpack-plugin *
      类似eslint, 对样式文件进行语法校验,支持.less和.scss

如何写一个plugin

推荐文章:webpack之plugin内部运行机制

  1. plugin是一个具有apply属性的函数对象,apply属性会被webpack compiler调用;
  2. 在apply方法中指定挂载的webpack事件钩子
  3. 在钩子回调函数内处理来自webpack实例的数据;
  4. 功能完成后调用webpack提供的callback

插件开发中一定要理解两个核心概念compilercompilation,此处简单概括下:

  • compiler对象代表配置完备的webpack环境,是针对webpack的
  • compilation对象针对的是随时可变的项目文件,只要文件有改动,compilation就会被重新创建。

show me your code:

// 首先定义一个函数作为插件实例,配置项options在这里处理
function MyWebpackPlugin(options) {
    // 接收options
}

MyWebpackPlugin.prototype.apply = function(compiler, callback) {
    // 对应编译周期内各个事件的钩子
    compiler.plugin('emit', function(compilation, callback) {
        // 创建一个头部字符串:
        var filelist = 'In this build:\n\n';

        // 检查所有编译好的资源文件:
        // 为每个文件名新增一行
        for (var filename in compilation.assets) {
        filelist += ('- '+ filename +'\n');
        }

        // 把它作为一个新的文件资源插入到 webpack 构建中:
        compilation.assets['filelist.md'] = {
            source: function() {
                return filelist;
            },
            size: function() {
                return filelist.length;
            }
        };

        callback();
    });
}

module.exports = MyWebpackPlugin;

webpack.config.js中引用插件:

var MyPlugin = require('MyWebpackPlugin');
module.exports = {
    // ...
    plugins: [
        new MyPlugin({
            options: true
        })
    ]
};

延伸:

  • 如何写一个loader
  • 使用nodejs搭建适合自己的脚手架

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.