由现象看问题
1. require也可以引入资源,为什么普遍用import呢?
2. import Vue from 'vue'
在 vue3 中改为了按需引入
import { nextTick } from 'vue'
这按需引入际上是在支持tree-shaking的特性,用到哪一个就导出具体的,以便去掉用不上的代码
Tree Shaking是基于ES6模板语法(import与exports),所以只支持ES模块的使用,不支持require这种动态引入模块的方式。
es的import引入是静态引入,主要是借助ES6模块的静态编译思想,在编译时就能确定模块的依赖关系,以及输入和输出的变量。commonjs的require引入是动态引入。
结论:建议在项目中引入,统一使用es6的import与exports。
回溯一波: AMD CMD commonjs UMD ES Module 区别
AMD:代表作requireJS,依赖前置,依赖全部先在define中定义加载好。文件并行加载
define(['jquery'], function(jquery){ // 工厂函数
function myFunc(){};
return myFunc;
})
CMD:代表作seaJS,就近加载资源,用到require
define(function(require, exports, module) {
var jquery = require('./jquery');
exports 或者module.exports导出
})
commonjs: Node的规范
var $ = require('jquery');
module.exports = myFunc(){};
UMD:(兼容全局变量、AMD、CMD和CommonJS)
umd想做到大一统,代码是各种判断,兼容各种规范.
ES Module:es6定义的规范语法,根正苗红。
为了向下兼容,一些包还是会使用babel转换为更广泛兼容的 CommonJS 模块或者UMD
var year = 1958;
export {year};
import {year} from './qq'
问题1: 上面提到一些包会打包为CommonJS ,而tree-shaking又只支持es Module,这样是不是会打包进去很多无用代码?
-
babel7:@babel/preset-env (一般脚手架自带) 配置"modules": false实现让代码保留es 引入
babe功能:会根据目标环境选择不支持的新特性来转译babel以前有各种插件:babel-preset-es2015,2016,2017 ,后来统一成 babel-preset-env,现在更名为最新的 @babel/preset-env
在.babelrc或 中 package.json中配置 "modules": false,将保留 ES 模块
这允许 webpack 进行tree-shaking,然后再将代码转换为广泛兼容的格式
{
"presets": [
[ "@babel/preset-env", {
"targets": {
"safari": 10
},
modules 默认值是auto,会自己判断是否需要转换
可选"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false
"modules": false,
useBuiltIns配置如何@babel/preset-env处理 polyfill。
"useBuiltIns": usage, // "usage"| "entry"| false,默认为false。
默认为"2.0", 仅当useBuiltIns不为false 才生效
"corejs": 3,
"debug": true
}]
]
}
引申思考:如何按需引入polyfill?core-js2, core-js3配合env怎么使用?
插件:@babel/polyfill ( 已在 7.4.0 中弃用)
是对 core-js 的封装,引用了 core-js 的内容和生成器(regenerator-runtime)
目前 Vue Cli 3 集成了 core-js 2,不支持升级到 3,无法手动升级。需要等待 Vue Cli 4
在业务项目中需要用到polyfill时, 可以使用
@babel/preset-env 的 targets 和 useBuiltIns: usage来根据目标浏览器的支持情况,按需引入用到的 polyfill 文件。
以下不建议:
不建议使用 import‘@babel/polyfilll’一次性引入所有的polyfill 文件
// 之前一次性引入:import "@babel/polyfill";
//直接引入corejs
import "core-js/stable";
import "regenerator-runtime/runtime";
-
查看依赖包的版本,辨别是否有支持导出es module 的模式
因为:依赖以 CommonJS 格式(例如,module.exports)导出内容,则该代码将不会被 webpack tree-shaking掉
比如Lodash 提供了lodash-es,element 有按需引入 -
项目中工具类函数文件utils单独导出函数,按需引入
单独导出函数
export function square ( x ) {
return x * x;
}
export function cube ( x ) {
return x * x * x;
}
- 注意副作用: 全局变量 以及 模块中类未被引用的方法 摇不掉。rollup在线代码验证
问题2:单纯的引入一份导出的文件,却不使用它的任何方法,这份文件代码也会被打包吗??我在一些老文章中看到会被打包
实验结果:最新的webpack4 rollup不会打包没有用到的代码
在webpack中
image.jpeg
image.jpeg
在webpack中引入单个方法并使用,会被打包
image.jpeg
image.jpeg
rollup中打包
image.jpeg
以上的rollup 是使用的vite项目打包: Vite 在开发模式下不需要打包可以直接运行,使用的是 ES6 的模块化加载规则,生产环境用 rollup
rollup有程序流分析的功能,可以更好的判断代码是否真正会产生副作用。更好的执行tree-shaking
关于vite的代码压缩,上图中可以看到一些信息
1.vite的使用brotli算法压缩,目前nginx并不直接支持,需要配置
2. 压缩率更高,文件更小。但是浏览器支持情况不怎么样,可以到can i use 去查看
3. 而且只有在HTTPS的情况下,浏览器才会发送br这个Accept-Encoding
Brotli压缩算法的浏览器使用的内容编码类型为br,如果服务端支持Brotli算法,则会返回以下的响应头
Accept-Encoding: br //gzip, deflate, sdch,
问题3、Runtime + Compiler => vue3(vue-next)源码
企业微信截图_16232934488073.png记忆:
1. 对于 runtime-compiler 来说,它的代码运行过程是:template -> AST树 -> render函数 -> render函数生成VDom -> UI
2. runtime-core中包含render渲染VDom,diff过程,所以runtime-only下在main.js中挂载元素直接是render写法:h('div'),render -> VDom -> UI,少了前三步
具体区别看这里对Vue中 runtime-compiler 和 runtime-only 两种模式的理解
问题4、vue是怎么实现跨平台能力的?
根据第一篇vue3 diff第一篇:diff算法代码解析可以知道元素需要挂载,移动。而在不同的平台的元素操作基础方法是不一样的
-
以浏览器为例:抽象出选择dom:document.querySelector,移动dom的方法
企业微信截图_16233078833453.png -
渲染器createRenderer 函数接收一个参数 options,该参数的作用是为了允许外界有能力将操作元素的具体实现以选项的方式传递进来
企业微信截图_16233079111830.png
网友评论