IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> babel转换class时使用defineProperty导致的装饰器问题 -> 正文阅读

[JavaScript知识库]babel转换class时使用defineProperty导致的装饰器问题

脑子一片混乱,搞了大半天虽然把问题解决了,但总高兴不起来,工程化能力太弱,每次都遇到各种奇葩的问题,让我都快要从入门到跑路了,说不定是从入门到入土(前段时间看到有人这样说,很好玩,抄袭一下,哈哈)。

话不多说,先说结论,故事慢慢再讲。

  1. react-scripts中的webpack配置在打包时,使用的是@babel/plugin-transform-class,并不会用typescript进行编译
  2. @babel/plugin-transform-class对类中字段的转码使用的是defineProperty,大部分情况下没有问题,但是在跟类属性的装饰器一起使用时导致装饰器失效,并不会报错:(

解决办法,在babel-loader处理之前添加ts-loader,先让typescript来转码。好了,开始讲故事了:)

背景是要把现有的一个项目改造成create-react-app创建的项目时遇到的问题。原来项目用的是rollup打包的。使用npx create-react-app project-name --template typescript创建一个空的项目,然后把代码拷贝过来。做了简单的修改,项目就这样跑起来了,我以为这样就结束了,可是我却不知道噩梦刚刚开始。

其实大部分功能都是正常的,唯独一个场景。最后分析下来是修改字段时并没有触发set,其背后的重绘逻辑也没有得到执行。经过提炼后的源码大概是这样的

class Student {
	@dirty
	name: string = '';

	dirty() {
		console.log('学生属性变化了,需要重绘哈');
	}
}

function dirty(target, key) {
	const backedKey = `__${key}__`;
	Object.defineProperty(target, key, {
		get() {
			return this[backedKey];
		},
		set(value) {
			if (this[backedKey] !== value) {
				this[backedKey] = createProxy(value, () => {
					this.dirty();
				});
				this.dirty();
			}
		},
		enumerable: true
	});
}

经过对比前后两个项目打包后的结果我发现,老的打包结果如下

function Student() {
	...
	this.name = '';
	...
}

而新的打包结果是

function Student() {
	Object.defineProperty(this, 'name', {});
}

那么问题就找到了。前者在new时,会执行this.name = ‘’, 这样就会触发set函数,以后再修改实例的name属性时也会触发set。但是后者因为在构造里使用defineProperty给实例添加了name属性,那么以后再修改实例的name属性也不会执行原型链上的set,因为实例本身是有name属性的。下面就看怎么解决了。

刚开始我是一头雾水,因为到此时其实我不知道react-scripts的项目打包时并不会用typescript进行转码的,因为我一直认为我创建项目时用了typescript的模板,而且我写代码也是按照typescript的预发写的,我就错误地认为也会使用typescript进行转码。后面是因为看了react-rescripts的源码中的webpack.config.js才知道。其实我感觉我这里说的不严谨,虽然webpack.config.js对于ts文件只用了babel-loader,但是应该不能说它没有用typescript转码,否则那么多ts语法是怎么转换的呢?

我的解决方案是在webpack.config.js中添加ts-loader。众所周知,不能直接修改webpack.config.js文件,因为它在node_modules中。那么要怎么做呢?这一点难不倒聪明的开发者,已经有人提供了rescripts用来修改webpack的配置。前段时间我出于好奇浏览了一下rescripts的源码,对它的原理有所了解,感兴趣的小伙伴可以移步这里

// 这是.rscriptsrc.js文件的内容
module.exports = {
	webpack: config => {
		const { loader, options } = config.module.rules[1].oneOf[3];
		config.module.rules[1].oneOf[3].use = [{ laoder, options}, 'ts-loader'];
		delete config.module.rules[1].oneOf[3].loader;
		delete config.module.rules[1].oneOf[3].options;
		return config;
	}
}

不要忘记安装rescripts和ts-loader哈。至此问题就解决了。也让我对前端又害怕了一分,工程化这种东西太浪费精力了,而且解决之后也没有太大的成就感,琐碎的东西还挺多,有些时候现成的工具只能去巴拉源码,苦呀,还是自己能力不够啊!

如果对你有帮助,请帮忙点赞哦,嘻嘻:)

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 18:55:10  更:2022-08-19 18:58:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:43:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码