webpack 笔记(二)

笔记(二)

1 Tree Shaking

  • 只支持ES Module(静态引入),也就是用import export导入导出。
  • 作用:一个模块中有多个内容,通过Tree Shaking可以控制只导出使用过(引用)的内容(方法),未使用过的不会打包到main.js文件中。

1.1 优化(optimization)配置与使用

  • optimization配置项:
开发环境:
webpack配置
module.export = {
    //优化配置项
    optimization: {
//把运行时用到webpack的源代码或运行时用到的代码
//放到runtime的一个Chunk里边去
      runtimeChunk: {
        name: 'runtime'
      },
    //设置为true,package.json中可以
    //定义一些文件不会被tree Shaking
	  usedExports: true,
	  splitChunks: {
	      //代码分割打包配置
	  }
    }
}
packag.json:
{
    "name":xx,
    //false表示对所有模块都进行Tree Shanking
    "sideEffects": false,
    //或设置为数组,放入忽略样式模块
    "sideEffects": [
        "*.css"
    ]
    ..
}

例子:
index.js:
//只引入add方法
import { add } from './math.js'
add(1, 2)

development(开发环境下)
main.js
/*! exports provided: add, minus */
/*! exports used: add */
production(上线时)
main.js中无minus这个方法(因为没有被使用)

2.1 Development和Production模式的区分打包

  • 将webpack.prod.js、webpack.dev.js、webpack.common.js三个配置文件放在build目录,记得修改output的dist路径
webpack.common.js
    plugins :{
    //传参数root表示清空上一级目录中的dist
        new CleanWebpackPlugin({
            root: path.resolve(_direname, '../')
        })
    },
	output: {
		//表示打包后的js文件名
		filename: '[name].js',
		//表示输出路径,要加绝对路径,所以引用path模块
		path: path.resolve(__dirname, '../dist')
	}
  • development开发环境下,生成的source-map文件会比较详细。(devtool:‘cheap-module-eval-source-map’,optimization:{usedExports: true})
package.json:
  "scripts": {
    "watch": "webpack --watch",
    //开发时:
    "dev": "webpack-dev-server --config webpack.dev.js",
    //上线时:
    "build": "webpack --config webpack.prod.js"
  }
  • 创建webpack.common.js把公共部分放一起。安装使用webpack-merge。
安装:
npm install webpack-merge -D
使用:
(webpack.dev.js)
const merge = require('webpack-merge')
const commonConfig = require('./webpack.common.js')
const devConfig = {
    //把module.exports对象中的内容都丢过来
}
module.exports = merge(devConfig, commonConfig)

2.2 Webpack和Code Splitting(代码分割)

https://webpack.js.org/guides/code-splitting/#root

  • Code Splitting:本质就是将项目js文件分类拆分成多个js文件,使页面可以异步加载多个js文件(一般最多5个,入口页面3个),不需要变动的部分缓存,提高复用率,后续业务逻辑发生变化,只需重新加载修改后main.js中的代码即可。
  • 如何分类:例如缓存组中vendors放置的是node_module中用到模块的js文件,这部分代码在后续会用到,可以缓存起来,提高复用率。
  • 三种方法:入口点(手动拆分)、防止重复(利用SplitChunksPlugin)和动态导入(模块内联函数调用拆分代码)
  1. 入口点(手动拆分)
安装:
npm install lodash

手动拆分代码:

webpack.common.js:
entry: {
    lodash: './src/lodash.js',
    main: './src/index.js'
}
  1. 防止重复(SplitChunksPlugins)
  • 使用splitChunksplugins实现同步和异步的代码分割:
配置:
common.config.js:
module.exports = {
    optimization: {
        splitChunks: {
        //不区分同步异步实现代码分割
            chunks: 'all'
        }
    }
}
  1. 动态导入
异步导入加载lodash:
index.js:
function getComponent() {
    return import(/* webpackChunkName: "lodash" */ 'lodash').then(({ default: _ }) => {
    const element = document.createElement('div');
    element.innerHTML = _.join(['Zeg', 'Tsai'], '_');
    return element;
  })
}

getComponent().then(element => {
  document.body.appendChild(element);
})

2.3 cacheGroups(缓存组)

  • 分为:vendors/default,vendors优先级默认更高。
  • 使用SplitChunksPlugin进行代码分割时,被引用的依赖模块(/node_modules/)的js文件会被打包到缓存组中vendors这一项,默认命名规则:vendors~引用的模块.js。其他默认规则。

2.4 SplitChunksPlugin配置参数

https://webpack.js.org/plugins/split-chunks-plugin/#defaults

  • 动态引入时配置语法:,目的就是改变异步拆分生成的文件名。
  • 关于拆分后js文件名字同步可以直接在cacheGroups中的分组vendors或default中添加filename改变打包后的文件名。而异步则需通过import(/* webpackChunkName: '' */ 'jquery').then()改名。
异步加载修改生成文件名字步骤:
1. 利用自带的动态引入模块插件:
.babelrc:
{
    "plugins": ["@babel/plugin-syntax-dynamic-import"]
}
2. 将缓存组的两项都设为false
common.config.js:
module.exports = {
	optimization: {
		splitChunks: {
			chunks: 'all',
			cacheGroups: {
//设为false,目的是不让默认配置缓存组匹配修改名称
//使得动态引入插件能成功修改生成文件的名字
//都设为false是为了让动态引入插件生效
                vendors: false,
                default: false
            }
	   }
	}
}

3. 在引入时加入/* webpackChunkName:"" */
index.js:
function getComponent() {
//将分割的文件起名为lodash.js
  return import(/* webpackChunkName:"lodash" */ 'lodash').then(({ default: _ }) => {
    let element = document.createElement('div');
    element.innerHTML = _.join(['Dell', 'Lee'], '_');
    return element;
  })
}

getComponent().then(element => {
  document.body.appendChild(element);
});
  • SplitChunksPlugin默认配置项
module.exports = {
  //...
  optimization: {
    splitChunks: {
    //只对异步代码有效
      chunks: 'async',
      //默认大于29.29kb模块才会实现分割
      minSize: 30000,
      //有设置的话,可能使代码进一步拆分
      maxSize: 0,
      //引用次数(大于一次就会分割打包)
      minChunks: 1,
      //最大异步请求(分割数)
      maxAsyncRequests: 5,
      //入口文件最多请求3个
      maxInitialRequests: 3,
      //生成文件名的连接符
      automaticNameDelimiter: '~',
      //文件名长度
      automaticNameMaxLength: 30,
      name: true,
      //缓存组
      cacheGroups: {
//同步代码这部分代码值不能都为false
//引用node_modules中的模块会打包到vendors这个组
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          //同时符合条件时的优先级(-10优先级高)
          priority: -10,
          //自己加的,同步有效
          filename: 'vendors.js'
        },
        //默认打包到这个组
        default: {
          minChunks: 2,
          priority: -20,
          //会复用已打包的模块
          reuseExistingChunk: true,
         //自己加的,只对同步有效
          filename: 'common.js'
        }
      }
    }
  }
};

3 Lazy Loading 懒加载

  • 入口页面只加载部分js和html,只有在满足(触发)某些条件时,再会使页面加载一些js、html等等的文件。

3.1 Chunk

  • 可以理解为引用次数
懒加载的例子:
index.js:
function getComponent() {
  return import(/* webpackChunkName:"lodash" */ 'lodash').then(({ default: _ }) => {
    let element = document.createElement('div');
    element.innerHTML = _.join(['Zeg', 'Tsai'], '_');
    return element;
  })
}

document.addEventListener('click', () => {
  getComponent().then(element => {
    document.body.appendChild(element);
  });
})

ES7:
async function getComponent() {
  const { default: _ } = await import(/* webpackChunkName:"lodash" */ 'lodash')
  const element = document.createElement('div');
  element.innerHTML = _.join(['Zeg', 'Tsai'], '_');
  return element;
}

document.addEventListener('click', () => {
  getComponent().then(element => {
    document.body.appendChild(element);
  });
})

3.2 打包分析,Preloading,Prefetching

https://github.com/webpack/analyse
https://webpack.js.org/guides/code-splitting/#bundle-analysis

  • 打包分析:利用工具分析打包是否合理。
package.json:
"dev-build": "webpack --profile --json > stats.json --config ./build/webpack.dev.js"

生成stats.json
需要进入webpack.github.io/analyse/
在线工具打包分析
  • prefetch:将来某些导航可能需要资源。
    preload:当前导航期间可能需要资源。
    错误地使用webpackPreload实际上会损害性能,因此在使用它时要小心。
  • 使用:/* webpackPrefetch: true /
    /
    webpackPreload: true */
  • 与prefetch相比,Preload指令有很多不同之处:
1. 预加载的块开始与父块并行加载。
   父块完成加载后,将启动Prefetch的块。
2. 预加载的块具有中等优先级并立即下载。
   浏览器空闲时下载Prefetch的块。
3. 父组块应立即请求预加载的块。
   未来的任何时候都可以使用Prefetch的块。
4. 浏览器支持是不同的。

4 Shimming(匀场模块,填隙?)

  • 作用:把一些全局依赖(如jQuery)以标识符($)的变量形式作为引入使用。

4.1 ProvidePlugin(自带插件)

  • 由于模块间有相互独立性,引用外部的包时,在别人包内添加自定添加的一些标识符(例如$表示引入jQuery)会很麻烦,通过这个插件可以创建一些通用标识符,在所有模块中使用该标识符,即代表引入该模块。
例子:
common.config.js:
const webpack = require('webpack');

const commonConfig = {
    entry:...
    ...
    plugins: [
    new webpack.ProvidePlugin({
    //只要模块使用$就会自动引入
        $: 'jquery',
    //只要使用_join就会到lodash中找到该函数(方法)
		_join: ['lodash', 'join']
    })
    ]
}
  • webpack中默认this指向的是自身的模块对象,非window,使用imports-loader可以解决这个问题。
按照:
npm install imports-loader -D

使用:
{
//兼容低版本的浏览器,配置文件在.babelrc中
	test: /\.js$/,
	exclude: /node_modules/,
	use: [{
		loader: 'babel-loader'
	}, {
	//使模块中的this指向window
    	loader: 'imports-loader?this=>window'
	}]
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值