分类
vue

升级 Vue@2 项目到 Vue@3

这篇主要是笔记。(我估计会是第一篇,因为只迁移了一个项目)

1. 安装新包

只记录必须重装的:

npm i vue@3 vue-loader@16.0.0-beta.8 vue-router@4.0.0-beta.13 @vue/compiler-sfc

2. 修改 Webpack 配置

// v2
const VueLoaderPlugin = require('vue-loader/lib/plugin');
// v3
const {VueLoaderPlugin} = require('vue-loader');

// for DefinePlugin
{
  plugins: [
    new DefinePlugin({
      __VUE_OPTIONS_API__: true,
      __VUE_PROD_DEVTOOLS__: false,
    }),
  ],
}

3. 修改入口文件

没有 new Vue({}) 了,取而代之的是 Vue.createApp({}),后者还支持 tree-shaking。

也不需要注册 Vue-router 了,直接 app.use(router) 就好。所以传统的入口文件就要修改为:

// v2
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './app';
import 'bootstrap/dist/css/bootstrap.min.css';
import '@/styl/index.styl';
import router from './router';

Vue.use(VueRouter);

Vue.config.productionTip = false;

new Vue({
  router,
  ...App,
}).$mount('#app');

// v3
import {createApp} from 'vue';
import App from './app';
import 'bootstrap/dist/css/bootstrap.min.css';
import '@/styl/index.styl';
import router from './router';

const app = createApp({
  ...App,
});
app.use(router);
app.mount('#app');

4. 修改 router

Vue-router 的变化很大,建议大家好好看看 迁移手册。就我厂这个项目而言,主要是三个变化:

  1. 使用支持 tree-shaking 的函数 createRouter
  2. 修改 history: createWebHistory()
  3. 使用渲染函数 h 替换之前渲染方式
// 加载方式
import {h} from 'vue';
import {
  createRouter,
  createWebHistory,
  createWebHashHistory,
  RouterView,
} from 'vue-router';

const routes = [
  {
    path: '/',
    name: 'home',
    component: {
      // vue-router v3
      render(createElement) {
        return createElement('router-view');
      }

      // vue-router v4
      render() {
        return h(RouterView);
      },
    },
    children: components,
  },
  // ....
];

const router = createRouter({
  // vue-router v3
  mode: process.env.NODE_ENV === 'production' ? 'history' : 'hash',
  // vue-router v4
  history: process.env.NODE_ENV === 'production'
    ? createWebHistory()
    : createWebHashHistory(),
  scrollBehavior: (to) => {
    if (to.hash && !/^#/.test(to.hash)) {
      return {selector: to.hash};
    }
    // 这里有个小改动,x => left, y => top,简单提一下
    return {top: 0};
  },
  routes,
});

5. 自定义组件 v-model 修改

  • prop: value => modelValue
  • event: input => `update:modelValue`

6. 一些小修改

  • beforeDestroy => beforeUnmount

7. createApp 与 Application,与 Component

v2 时,我们可以通过 new Vue({}) 初始化 Vue 实例。这个阶段,Vue 默认有一个全局对象 + 若干个实例,除了 local 的,就是全局的。

v3 时,引入了 Application(应用)的概念,在全局和组件之间,增加了一个新的层级。这样一来,我们就可以在同一个 Web 产品中,使用 Application 来划分命令、组件、mixins 的范围。应该会增加代码的强壮程度(虽然我暂时还没用到)。

不过,迁移代码的时候,也要注意。以前我们可能 new 一个实例,调用它的 methods;现在不行了,要这样做:

// v2
const ins = new Vue({});
ins.doSomething();

// v3
const app = createApp({});
const vm = app.mount('$el');
vm.doSomething();

8. 新的响应式 API

v3 最大的变化就是重构了响应式实现,所以新增了不少响应式 API。同时,也会检查开发者的代码,如果发现不需要响应式的地方用到响应式对象,就会提示开发者,因为响应式会增加系统开销。

这个时候可以用 markRawtoRaw 方法来修改对象,撤销之前附加在上面的响应式属性,提高访问效率。

其它 API 还很多,后面慢慢更新吧。

9. Devtool 和 SourceMap

遗憾的是,目前 Vue Devtool 无法检测到 Vue。老项目的 SourceMap 也完全不生效,无法正常对 SFC 进行 debug。

分类
vue

webpack 入口是 vue 文件时,无法合并 CSS

在多页网站中合并 CSS 是很常见的优化手法。一般来说,CSS 体积不会太大,使用同一份 CSS,改进用户点击链接后的加载速度,大部分收益都大于多加载几 K CSS 带来的损耗。

对于 UI 库来说也是如此,用统一的样式库,减少 import 时的心智负担,也是性价比很高的做法。

最开始我在 UI 库的入口文件里 export 所有组件,然后在其它仓库里用 import {component} from 'my-components' 使用组件。后来通过分析得知,这样做无法 tree-shaking,而且会导致组件库的重复引用,即 A import B,B import C,那么无论 A 里有没有用到 C(比如用到 B 的一个小功能 b1,它不依赖 C),都会把 C 的代码打包进去。

通过研读 Webpack 的 tree-shaking 文档,我得知也没有什么好办法可以规避这个问题,毕竟 JS 很灵活,你也不知道哪个开发者会搞个 eval('const myRequire = require'),如果要识别解析分辨所有情况太复杂,所以选择最保守的策略:认不出来具体功能的代码都给你带上。(早年我写 NerveNet 的时候,就是想不通这里怎么搞,最后坑掉了。早知道大家都选择绕开,说不定我的 NerveNet 也能如愿写出来了……)

总之,目前 lodash 的做法比较常见且能解决问题,即增加多入口,为每个可能用到的函数都打包独立的函数。这样需要引用那个就引用哪个,不用担心把整个 lodash 都打包进去。

于是我就立项开始重构我厂的几个前端库。然后很快就卡在 UI 库上面:无法生成合并过的 CSS 文件。Google 许久没有结果,吃饭前我灵机一动:vue-loader 必须搭配 VueLoaderPlugin 才能正确打包,会不会这个过程有 bug,导致如果我的入口都是 Vue 单文件组件,就会没法正确合并 CSS 文件。

然后我就测试了一下,代码大约如下:

// a.js
import './a.styl'

// b.js
import './b.styl'

可以生成合并过的 CSS 文件。与之相较,这样的 Vue 单文件组件就不行:

// a.vue
<style lang="stylus">
body
  font-size 16px
</style>

// b.vue
<style lang="stylus">
body
  color red
</style>

但是,同样是 vue 单文件组件,样式使用 import 的方式导入,就没问题:

// a.vue
<script>
import './a.styl';
</script>

// b.vue
<script>
import './b.styl';
</script>

现在可以确定是 vue-loader 或者 VueLoaderPlugin 有问题。不过最近身体欠佳,每天要花很多时间锻炼,另外还欠下不少坑要填,所以暂时没空去翻 issue 或者提 issue。哪位同学看见了,愿意帮忙的,可以搞一下,也算参与 开源社区建设了,功德无量。

分类
vue

Vue 3.0-beta.1 发布!

经历一年多的推倒重来反复打磨,在众多开发者的千呼万唤之下,Vue 开发团队终于在今天发布了 3.0-beta.1 版本,也就是测试版。通常来说,从测试版到正式版,只会修复 bug,不会引入新功能,或者删改老功能。所以,如果你对新版本非常感兴趣,或者有新项目即将上马,不妨尝试一下新版本。

按照官方路线图,原计划 Q1 末发布测试版,Q2 发布正式版。目前看来稍微有些延期,不过不多。相信正式版会很快到来,非常期待呀。

在我看来,Vue 已经是一份杰作,而 3.0 的变化则让它更加优秀。

起初,Vue 开创性的使用 Object.defineProperty 改写对象属性赋值运算,隐性收集依赖,把前端开发的难度降低了一个维度。从此,我们不需要考虑怎么绑定数据,怎么更新视图,只需要简简单单修改变量的值,界面就会自动变化,如魔法一般。

如今,Vue 3.0 更进一步,使用 Proxy 拦截赋值操作,不仅实现了同样的功能,还大幅降低系统消耗、减少计算时间。——更加值得期待的是,因为新 API 更强大,之前困扰众多开发者的“修改数据,界面不更新”问题,应该会变得极为罕见。

这会令 Vue 的入门门槛变得更低。在我看来,这件事善莫大焉。写代码并不仅仅是写代码,它是这个世界上成本最低的“创造型”工作。其它创造型工作,比如雕塑、美术,除了复杂的基础教育,还需要昂贵的生产成本。编程不需要,只要你有一台电脑,坐下来就可以写,想怎么写就怎么写,想写什么就写什么。而前端,又是其中成本最低的,你甚至不需要搭建开发环境,拿个记事本就能写,写完放到浏览器里就能跑。

从这个角度出发,每次在知乎看到“我出身不好,能不能学编程”,或者“我学历不好,能不能学编程”,我都会建议他们学。因为学会编程,不仅仅是掌握一门手艺,可能养家糊口,更是给自己的未来增加了一种可行性。学会编程,你就可以把手伸到我这种专业程序员伸不到的地方,帮助自己、帮助他人、甚至帮助世界,同时也能给自己换来各种各样的回报。

另外,新增的 Composition API——不管是一些人口中的“学 React hooks”,还是 Vue 作者尤雨溪说的“这不是 hooks,这比 hooks 强太多了”——大大增强了代码的可复用性,能很好的改进代码架构,为更大的项目、更强的架构,带来了更多的可能。

如果说 jQuery 让更多的人可以学会开发,那么 Vue 就让更多的人可以开发中大型软件。它会给整个行业带来的巨大帮助,让更多的产品可以有更好的用户体验,让更多的产品可以迁移、升级到新平台、新架构。

这个影响是潜移默化的,就像当年 Flash Player 集成 H.264 视频解码器一样,虽然很多人没注意,但是视频网站的春天就是那个时候到来的。如今,有了更好的基础设施,哪个新产品会崛起,我无法判断,但我觉得,对技术来说,更好的一天已经开始了。

分类
vue

Vue 2020 年路线图,Vue 3.0 计划于 Q2 发布

昨天 Vue 团队更新了 2020 年的路线图,里面包含了很多 Vue 3.0 的信息。建议大家一定要看原文,地址在:https://github.com/vuejs/vue/projects/6。下面我结合自己的理解翻译一下:

FAQ

问:3.0 啥时候能好?

答:请往后看。另外请注意,这些日期仅供参考,我们团队的首要目标是发布生产级别的高质量代码,不是赶 deadline。

问:3.0 里都有啥变化啊?

答:请自行翻阅最新的 RFC。另外,也要注意核心团队提交的 RFC 草案。

如果某个 RFC 里包含破坏性变更,那么里面一定会有“升级策略”章节,讨论迁移问题。

对于现在的 2.x 用户,我们会提供:

  • 迁移向导
  • 能够兼容 2.x 的兼容性版本(如果能兼容的话),并且对该升级的地方给出提示和升级建议
  • 命令行迁移工具
    • 自动升级能升级的代码
    • 不能自动升级的,扫描出来提示手动升级

问:我是新人,我现在该学 Vue 2.0 还是等 3.0?

答:如果你刚刚开始学习框架,那么应该开始使用 Vue 2。我们没有对 Vue 3 进行巨大的重新设计,所以大部分 Vue 2 知识仍将适用于 Vue 3。 如果你打算学习框架,没有必要等待。

如果你要为某个生产级别的项目选择技术栈:

  • 如果项目需要立即动工:我们仍然建议使用 Vue 2,以便获得完整的、框架级别的支持。 但是,也请留心 3.0 中即将发生的更改,不要使用将被移除的功能,最好也不要使用与 Vue 2 深度耦合的第三方依赖。
  • 如果项目可以等到 Q2 末:那我们建议你等等,用 3.0。

问:以后 2.x 会咋样呢?

答:接下来会有一个小版本(2.7)更新:

  • 将兼容的 3.x 功能反向移植回 2.x
  • 对 3.x 弃用的功能发出警告

这是 2.x 最后一个小版本,并提供长达 18 个月的 LTS(长期支持)。即使在 LTS 结束之后,我们也会继续提供重要的安全更新。

问:Vuex 方面有什么计划么?

答:一方面,我们正在开发Vuex(4.0)版本,其 API与 当前版本(3.0)完全相同,但与 Vue 3 兼容。我们力求向下兼容,让用户可以在 Vue 3 项目中继续使用现有 Vuex 代码。

另一方面,我们也在尝试新的设计,更多的利用 Vue 3 的响应式 API,也让 Vuex API 不那么冗长。 这个新版本暂定为“ vuex-next”,也就是 5.0。 眼下,我们只是在进行早期探索,最早也要到 2020 年第三季度才会发布。

2020 一季度计划

  • 3.0 SSR
  • 3.0 迁移
    • 升级向导(施工中)
    • 2.x 兼容版本
    • 迁移工具
  • 3.0 框架
    • router(施工中)
    • Vuex(施工中)
    • 测试工具(施工中)
    • JSX babel 插件(施工中)(我以为不会有这个东西了呢)
    • CLI
    • Devtools
    • 其它(虽然最后三个没标施工中,不过我觉得多半也是在施工中咯)
  • 3.0 beta
    • Q1 末发布!
    • 3.0 核心现在其实已经完成了,我们希望 API 到这个时候也能稳定下来。
    • 我们还需要更多的时间才能更新周边的库和工具。 如果您的使用场景对 router 和 vuex 没有硬性要求,这个时候就可以开始使用 3.0 了,但最好是非关键性应用程序。

2020 二季度计划

  • 继续之前未完成的 3.0 框架工作
  • 季度中,发布 3.0 RC
    • 冻结 API,不再有重大变化。进入 RC 之前,所有涉及到重大变更的 RFC 都要定案。
    • 全家桶能够和 3.0 版本协同工作。
    • 3.0 版本就绪,此阶段基本可用。仍然会有一些小错误和框架集成问题,在 RC 阶段都会慢慢被解决掉。
  • 3.0 发布管理
    • 回归测试
    • 自动化每晚发布
    • 正式确定版本生命周期
  • 3.0 IE11 兼容性版本
  • 3.0 官方正式版

2020 三季度计划

发布 2.7 版本

  • 反相迁移 3.x 功能到 2.x
  • 对 3.x 中弃用的功能发出警告
  • 2.x 最后的小版本,LTS
分类
vue

迎接 Vue 3.0

思否(SegmentFault)去年引入了新的运营合伙人,大张旗鼓,计划重新梳理视频教程体系。第一个举措就是推出新系列:思否编程公开课。这个系列的优势在于结合社区运营的知识与一线讲师的实战能力:即社区寻找大家关心的话题,请相关领域的讲师来讲解,达到受众明确、内容扎实的目标。

很高兴能够得到邀请,做了一期《迎接 Vue 3.0》,我也趁机深入了解了一把 Vue 3.0。

Vue 3.0 原计划 2019 年发布,但是开发过程有些波折,一些早期的设计被放弃了,因为不够好;引入了新的更好的设计,于是延期至今,仍然是 alpha 版。在新的设计下,Vue 3.0 更快,快到不需要时间切片;而且还能基本保持与 2.x 版本的兼容。

至于新增的 Compisition API,其实是选修课,类似 Async 之于 Promise。有了它,我们能更好的复用代码、维护代码;不用它,也不耽误我们享受其它升级带来的便利。

其实看过很多 Vue 3.0 的东西之后,我越发感激开发团队为这个框架做得一切,越发感激开源文化为我们带来的新世界。

我备课一向认真充分,所以讲课的内容应该是现在最新最全面的,欢迎大家围观:【思否编程公开课】迎接Vue 3.0

分类
js 技术

在 Chart.js 的线图里增加竖线

我经常使用 Chart.js 生成图表,无它,名字好记+免费+持续更新。现在主要基于 Vue 开发项目,所以经常使用 vue-chart.js。前阵子遇到一个需求:

  1. 把一组数据画成线图
  2. 用户可以任意点击时间
  3. 用数据生成饼图

那么就需要在线图中画一条竖线,标识出当前时间点。本以为这个需求不复杂,没想到不仅 Chart.js 不支持,包含这个功能的插件因为 Chart.js 升级的关系,暂时没法用。所以只好自己实现。

分类
分享 技术

Chat idea:记一次 Firefox 下 Vue 带来的性能危机的解决

前两天遇到一个问题:我厂的一个产品在 Firefox 下,可能发生因为 CPU 占用过高而卡死的情况。这个问题在测试环境不复现,在 Chrome下基本上也不会复现。

因为我厂老板是这个产品的主要用户,这个 bug 让我倍感压力,但一直没有解决它的好办法。终于有一天,在某台生产机上调试另外一个 bug 的时候,我终于发现了稳定复现这个 bug 的方式。

接下来就是几个小时的 debug,然后发现问题所在,然后解决问题,然后发现解决方案不理想,于是寻求新的解决方案,然后找到新的 API,最终彻底的解决这个问题。

接下来我就分享这个过程,读完整篇文章当中你将学会:

  1. 使用开发者工具查找性能问题
  2. 不断切分,缩小问题范围
  3. 理解 Vue 响应式原理分析问题根源
  4. 修复问题并验证
  5. 新的解决方案 Intersection Observer
  6. 解决问题并上线

目标读者:

  1. 中级开发者
  2. 熟悉原生 JS

大家觉得这个 idea 如何?请留言告诉我。不出意外的话这将是我下个月的 gitchat 内容。


有同学在 Drift 里留言,这里更新回答一下:这篇文章最后没写,因为当时 GitChat 的编辑不感兴趣,所以就放弃了。将来有机会会写。

分类
分享

Chat Idea:扫雷网页版实战

最近最常玩的游戏是扫雷。年纪大了,干什么时候都先考虑成本,游戏也是如此。扫雷的成本最低,倒不是说购买成本,而是启动、游戏、退出之类的成本。

可惜的是,经典版扫雷已经从 Windows 10 里移除了,现在只能通过 Windows 应用商店装一个很复杂的扫雷游戏,花样多了很多,却并不好玩。所以我现在多半玩网页版。

玩着玩着,出于程序员的本能,我就开始考虑如何写这个游戏,逻辑不算复杂,功能点也不多,好像蛮适合做成“实战派”教程的,比如用 Grid 写界面,项目结构就用 Vue CLI 3 吧,然后部署的话前端纯静态就够了。

那么就愉快的决定了吧,把这个项目做出来,把中间需要的知识,用到的技能、工具,可能会遭遇的问题记下来分享出来,写成一篇文章,分享出去。读完整篇文章,你将学会:

  1. 使用 Vue CLI 3 搭建项目
  2. 使用 CSS Flex + Grid 完成页面布局
  3. 扫雷游戏的逻辑
  4. 使用 Vue 完成游戏逻辑
  5. 记录成绩
  6. 部署和分享

目标读者:

  1. 初级开发者,能看到一个项目的成型
  2. 希望了解现代化前端框架、工具链
分类
vue

Chat:Vue 进阶必经之路

Vue 进阶必经之路

Vue 的学习曲线平缓,入门很简单,所以后发夺人,争取到一大批支持者,我也是其中之一。但是因为隐蔽了很多细节,所以我也没少踩坑,挠头拍桌,不厌其烦。如今,我终于突破屏障,遇到大部分问题,都能举一反三,快速定位、快速解决。这段过程,难免追本溯源,穷究细节。我希望通过这次分享,把我的经验和收获传达给大家。

面向听众:

1. 有一定 Vue 开发经验,希望进一步提升;
2. 平时业务代码写得多,想学习技术细节。

写完了,不得不说,没有预先想象中写得好。原因嘛,当然是工作太忙,能够写文的时间不太够。以后还是平时多写,Chat 当汇总比较好。

不过还是希望大家都来看,毕竟我这两年踩坑得到的 Vue 经验都在里面了。

分类
js

CodeMirror 笔记

这篇文章用来记录使用 CodeMirror 时的一些心得。