Vue CLI 3 配置中 Modern mode 是什么

简介: 最近特别关注 vue-cli 3 的更新情况,有很多特别棒的新功能和特性,比如基于 UI 界面的项目管理器(参数配置、数据查看、插件安装一体的界面工具)、可配置的输出构建类型(App、库、组件、异步组件)、构建模式 Modern mode 等等。

最近特别关注 vue-cli 3 的更新情况,有很多特别棒的新功能和特性,比如基于 UI 界面的项目管理器(参数配置、数据查看、插件安装一体的界面工具)、可配置的输出构建类型(App、库、组件、异步组件)、构建模式 Modern mode 等等。下面我们重点关注下 Modern mode 是什么,如何实现的。

目录

  • Modern mode 是什么?
  • Modern mode 实现方式

Modern mode 是什么?

使用 Babel 我们能够利用 ES2015 中最新的语言特性,但这也意味着我们必须通过转换和 添加 polyfille 来支持旧浏览器。这些转换后的代码通常比原生 ES2015+ 代码更冗长,并且解析和运行较慢。鉴于当今大多数现代浏览器对原生 ES2015+ 有着不错的支持,而我们不得不将数据量更大和效率底下的代码发送给浏览器,因为我们必须支持那些旧的浏览器。

Vue CLI 提供了一个 Modern mode 来帮助您解决这个问题。用以下命令进行生产时:

vue-cli-service build --modern
复制代码

Vue CLI 构建两个版本的 js 包:一个面向支持现代浏览器的原生 ES2015+ 包,以及一个针对其他旧浏览器的包。

但最酷的部分是没有特殊的部署要求。生成的HTML文件中自动适配。 这个方式采用了Phillip Walton 文章中讨论的技术方案

  • 在支持原生 ES2015+ 的浏览器中,js会通过 <script type="module"> 加载,并且可以使用 <link rel="modulepreload"> 预加载。

  • 在不支持的浏览器中使用 <script nomodule> 来加载编译版本,并且这会被支持ES模块的浏览器所忽略。

  • Safari 10 中有一个小问题这里已经解决,可以自动加载。

对比 Hello World 应用(vue 初始化的 Demo)使用这种模式打包出来的文件,通过现代模式输出的包(以后简称现代包)已经小了16%。在生产中,现代包通常会显著的提升 parse 速度和加载性能。

Modern mode 实现方式

在浏览器环境语法特性检测还没有一个特别好的解决方案,随着一些新的 JavaScript 语法的出现,单凭特性检测来检查新语法的支持程度很是棘手。尽管如此对于 ES2015+ 的基本语法特性检测我们还是有办法的。解决之道便是 <script type="module">

大部分开发者认为 <script type="module"> 是用来加载 ES 模块的,但是这里使用是 <script type="module"> 的特性——加载浏览器可以处理的、使用 ES2015+ 语法的 JavaScript 文件。

换句话说,每个支持 <script type="module"> 的浏览器都支持你所熟知的大部分 ES2015+ 语法,例如:

  • 支持 <script type="module"> 的浏览器也支持 async 和 await 函数。
  • 支持 <script type="module"> 的浏览器也支持 Class 类。
  • 支持 <script type="module"> 的浏览器也支持 arrow functions。
  • 支持 <script type="module"> 的浏览器也支持 fetch 、Promises、Map、Set 等更多 ES2015+ 语法。

因此,唯一需要做的就是为不支持 <script type="module"> 的浏览器提供一个降级方案。对于支持 <script type="module"> 的浏览器会忽略 <script nomodule></script> 方式引入的脚本,如下代码:

// 支持的浏览器 会加载 app.js, 不支持的浏览器因为 type 值不是 text/javascript 所以脚本并不会被加载。
<script type="module" src="app.js"></script>
// 支持的浏览器 会忽略配置 `nomodule` 属性的脚本加载,不支持的浏览器会正常加载。
<script src="app-legacy.js" nomodule></script>
复制代码

下面看一下vue打包出来的代码:

// ...
<link as="style" href="/css/app.6166f93b.css" rel="preload">
<link as="script" href="/js/app.4e3e948a.js" rel="modulepreload">
<link as="script" href="/js/chunk-vendors.fcf87964.js" rel="modulepreload">
<link href="/css/app.6166f93b.css" rel="stylesheet">
// ...

<script type="module" src="/js/chunk-vendors.fcf87964.js"></script>
<script type="module" src="/js/app.4e3e948a.js"></script>
<script>!function () { var e = document, t = e.createElement("script"); if (!("noModule" in t) && "onbeforeload" in t) { var n = !1; e.addEventListener("beforeload", function (e) { if (e.target === t) n = !0; else if (!e.target.hasAttribute("nomodule") || !n) return; e.preventDefault() }, !0), t.type = "module", t.src = ".", e.head.appendChild(t), t.remove() } }();</script>
<script src="/js/chunk-vendors-legacy.ea74b83d.js" nomodule></script>
<script src="/js/app-legacy.854b5bc1.js" nomodule></script>
复制代码

之前说到现代浏览器中都可以通过 <script type="module"> 来实现 ES2015+ 的特性检测针对性的加载脚本,但是 Safari 10 除外,这里的一段脚本是修复 safari 10 上 nomdoule 的表现不同的:

<script>!function () { var e = document, t = e.createElement("script"); if (!("noModule" in t) && "onbeforeload" in t) { var n = !1; e.addEventListener("beforeload", function (e) { if (e.target === t) n = !0; else if (!e.target.hasAttribute("nomodule") || !n) return; e.preventDefault() }, !0), t.type = "module", t.src = ".", e.head.appendChild(t), t.remove() } }();</script>
复制代码

webpack 相关配置

如果你对 vue-cli 3 是如何实现这块的感兴趣可以查看源码

为了生成不同环境的js文件,你需要2个 babel-loader targets配置。

// resolve targets
let targets
if (process.env.VUE_CLI_BABEL_TARGET_NODE) {
  // running tests in Node.js
  targets = { node: 'current' }
} else if (process.env.VUE_CLI_BUILD_TARGET === 'wc' || process.env.VUE_CLI_BUILD_TARGET === 'wc-async') {
  // targeting browsers that at least support ES2015 classes
  // https://github.com/babel/babel/blob/master/packages/babel-preset-env/data/plugins.json#L52-L61
  targets = {
    browsers: [
      'Chrome >= 49',
      'Firefox >= 45',
      'Safari >= 10',
      'Edge >= 13',
      'iOS >= 10',
      'Electron >= 0.36'
    ]
  }
} else if (process.env.VUE_CLI_MODERN_BUILD) {
  // targeting browsers that support <script type="module">
  targets = { esmodules: true }
} else {
  targets = rawTargets
}
复制代码
ES2015+ 浏览器支持目标只需配置  babel-loader 参数  targets = { esmodules: true }即可。

示例代码块地址

preload 作为一个新的web标准,旨在提高性能,为web开发人员提供更细粒度的加载控制。preload 使开发者能够自定义资源的加载逻辑,且无需忍受基于脚本的资源加载器带来的性能损失。

preload 还有许多其他好处。使用 as 来指定将要预加载的内容的类型,将使得浏览器能够:

  • 更精确地优化资源加载优先级。
  • 匹配未来的加载需求,在适当的情况下,重复利用同一资源。
  • 为资源应用正确的内容安全策略。
  • 为资源设置正确的 Accept 请求头。

在 modulepreload 诞生前,还没有一种很好的声明式预加载模块的方法。Chrome 从 64 版本后 开始 “实验性的支持这个特征”。<link rel="modulepreload"> 是 <link rel="preload"> 的特定模块版本,解决了后者的一些问题。

总结:

启用该模式会自动构建两个版本的 js 包,针对支持现代浏览器的原生 ES2015+ 包,和针对其他旧浏览器的包,生成的 HTML 会通过 <script type="module"> 和 <script nomodule> 进行自动降级,不需要任何特殊部署配置。原生 ES2015 包几乎不需要任何 polyfill 和编译,代码尺寸更小,现代浏览器 parse 和运行也更快。

拓展阅读:

ES6 Modules in Chrome M61+
ECMAScript modules in browsers
ES6 Modules in Depth
Deploying ES2015+ Code in Production Today
Preloading modules


原文发布时间为:2018年07月02日

作者:掘金

本文来源:掘金 如需转载请联系原作者

相关文章
|
7天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
vue学习第四章
|
7天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
vue学习第九章(v-model)
|
7天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
vue学习第十章(组件开发)
|
13天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
12天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
12天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
存储 前端开发 JavaScript
为什么我不再用Vue,改用React?
当我走进现代前端开发行业的时候,我做了一个每位开发人员都要做的决策:选择一个合适的框架。当时正逢 jQuery 被淘汰,前端开发者们不再用它编写难看的、非结构化的老式 JavaScript 程序了。
|
13天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
13天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
13天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。

相关实验场景

更多
下一篇
无影云桌面