在 React 中,我制作了一个可以用 JSX 编写的库,用于在过度规范的情况下使用
React 和 SolidJS 等框架很有用。
社区和生态系统已经发展壮大,如果你用谷歌搜索,你会发现很多文章。
但是,根据场景,有许多不必要的功能。
所以,DOM 渲染什么时候JSX语法精髓一个超轻量级的库,只专注于JS博士我试图创造
▼ NPM 包是
▼ GitHub 仓库如下
特征
超轻
截至 2022/08/12,BundlePhobia 使用 zgip 压缩(未压缩 1.12kB)测量 657B。
我知道比较是冒昧的,但我也将其他库与 BundlePhobia 进行了比较......
图书馆名称 | 未压缩大小 | zgip 压缩大小 | 评论 |
---|---|---|---|
JS博士 | 1.12kB | 0.7kB | *1 |
反应 + 反应 DOM | 6.4kB + 130.5kB | 2.5kB + 42kB | *2 |
预演 | 10.3kB | 4kB | |
Vue.js | 95.3kB | 34.2kB | |
苗条 | 4.5kB | 1.7kB | |
SolidJS | 20.1kB | 7.1kB |
*1 这次创建的图书馆
*2 如果你在浏览器上使用它,你需要使用 React DOM 作为一个集合。
您会发现与其他库相比,它非常轻量级。
但是,即使添加到上述库webpack这样的项目中,大小也不会像JS文件大小(Tree Shaking)那样增加,因此仅供参考。
可以写成 JSX 格式
很难说这是否可以称为优势。
例如,<div className='sample'>TEXT</div>
在 React 中是
React.createElement('div', {className: 'sample'}, 'TEXT')
它只是语法糖,因此您最终将创建一个采用与此相同参数的实现。
出于这个原因,Hiroshi JS 可以用与 React 非常相似的方式编写,所以我认为可以肯定地说,一旦你接触了 React,几乎没有学习成本。
任何接触过 TypeScript 的人都可以实现的范围内的源代码
我敢肯定你不是唯一一个对 React 源代码发疯的人。
Hiroshi JS 是用 TypeScript 编写的,但是写的量非常少,所以我想大多数人都能看懂。
“我不知道为什么,但我很害怕 React 正在运行!”或者“如果 React 有一个致命的错误怎么办?”。
前者我还是懂的,但不知道还有没有后者的人……
▼截至2022/08/12,只写了97行处理。
假设用例
使用 jQuery 等将 HTML 作为字符串输出时。
它是由看到有人实现了以下 JS 触发的。
你还在用 jQuery 吗?我没有反思想的想法,但我不会用字符串组装HTML,(除了我是否咬JSX语法糖),我根据函数组装和输出HTML,当时它随意转义。认为如果有这样的机制,XSS漏洞是可以预防的。
// ※href や text 変数はエスケープされていないものとする
const href = '"><script>alert("アラート!!");</script>';
const text = '<style>* {display: none !important;}</style>';
// これでアラートが発火して、画面が真っ白になってしまう
// 各変数に replace を噛ましてエスケープするでも良いが、ヒューマンエラーも発生しそう……
$('#app').append('<a href="' + href + '">' + text + '</a>');
如果您浏览新创建的库,它将作为一种机制为您进行转义。
// 後述の手段で今回作成したライブラリの createElement メソッドを読み込んだ上で
// createElement は名称が長いので h 変数に突っ込む
const c = createElement;
const href = '"><script>alert("アラート!!");</script>';
const text = '<style>* {display: none !important;}</style>';
// h (createElement) 関数内でエスケープされる仕組みを提供
// ※ 以下の記述は JSX 構文を使用しない記述となります
$('#app').append(c('a', {href: href}, text));
如果每个人都不使用 jQuery 并使用 React、Vue.js 或 SolidJS,那就太好了,但世界上超过 80% 的网站1使用jQuery,所以我认为有很多地方可以使用这个用法示例。
基于 API 的 JS 的 HTML 输出,但如果之后状态没有变化
虽然 HTML 是基础后端输出的,但我们假设这个库在 API 传递部分内容,JS 渲染,以提高 CDN 的缓存命中率等情况下会有用,我来了。
如果你需要根据用户的操作响应式地重写 HTML,你可以使用 React、Vue.js 等,但是如果你只是想接收数据并将其输出为 HTML,那些库是过度规范的,这会导致JS 文件的包大小意外膨胀。
(如上所述,即使 Tree Shaking 在某种程度上与 webpack 之类的打包器一起工作,我认为也有一个限制,但实际上发生了什么......我想围绕这个积累知识。)
import * as React from 'react';
import {createRoot} from 'react-dom/client';
const App = props => {
const [apiData, setApiData] = React.useState([]);
// API を叩いて表示する
React.useEffect(() => {
fetch('/api/v1/path/to/api')
.then(res => res.json())
.then(res => setApiData(res));
}, []);
return <>{apiData.map(item => <Card {...item}/>)}</>;
};
const container = document.getElementById('app');
const root = createRoot(container);
root.render(<App />);
我认为它会在诸如点击这样的 API 并显示它的情况下变得活跃起来。
用法
CDN(可选)
▼ 如果不想用ES模块(怎么看<script src="xxx">
)
- https://cdn.jsdelivr.net/npm/hiroshi@latest/dist/umd/hiroshi.js
- https://unpkg.com/hiroshi@latest/dist/umd/hiroshi.js
* 看完上面的js文件,就可以用Hiroshi
对象访问了。
▼ ES模块格式(怎么写import xxx from 'xxx'
)
- https://cdn.jsdelivr.net/npm/hiroshi@latest/dist/esm/hiroshi.js
- https://unpkg.com/hiroshi@latest/dist/esm/hiroshi.js
JSX 格式
如上所述,它可以与 CDN 一起使用,但我们将继续解释,假设包是使用 npm 导入的。
安装 Hiroshi JS 后,
$ npm install hiroshi
相应地调整模块捆绑器或转译器中的 JSX 编译选项。
tsconfig.json
TypeScript 中的调整示例
* typscript
安装包后的设置(摘录)。
{
"compilerOptions": {
"jsx": "preserve",
"jsxFactory": "createElement",
"jsxFragmentFactory": "Fragment",
}
}
Babel 调优示例
* @babel/core
@babel/preset-env
@babel/plugin-transform-react-jsx
安装包后的设置(摘录)。
{
"plugins": [
["@babel/plugin-transform-react-jsx", {
"pragma": "createElement",
"pragmaFrag": "Fragment",
}]
]
}
说设置很麻烦的人
如果您将 Hiroshi JS 加载为 React,它将起作用。
* 未验证对TypeScript等类型设置严格时是否会输出错误。
import * as React from 'hiroshi';
const {createElement, Fragment, createRef} = React;
import {createElement, Fragment, createRef} from 'hiroshi';
以上两个描述运行相同的过程,因此请相应地阅读它们。
执行
由于它没有像 React 那样使用虚拟 DOM,而是直接返回原始 DOM,所以可以描述如下。
当然,字符串转义也是任意进行的,所以除非你故意插入危险处理,否则实现是不会发生XSS的。
import {createElement, Fragment, createRef} as React from 'hiroshi';
const style = {
marginBottom: "0.5rem",
border: "solid 1px #aaa",
padding: ".5rem",
flexBasis: "12rem"
};
const Card = (props) => (
<div className="card"
style={style}
onClick={e => alert(`Click: ${props.name}`)}>
{props.name}: {props.children}
</div>
);
const UserList = () => {
const ref = React.createRef();
fetch("//jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((res) => {
// API が読み込まれたら DOM を生成して ref を用いて置き換える
const {current} = ref;
current.replaceChild(
<>{res.map(({ name, username }) => (
<Card name={name}>{username}</Card>
))}</>,
current.firstElementChild
);
});
// API 読み込み中のメッセージを出しておく
return (
<div
className={"userList"}
ref={ref}
>
<span>Now loading...</span>
</div>
);
};
document.getElementById("app").appendChild(UserList());
我将省略详细解释(我可能稍后会添加),但我正在为 React 中的以下方法创建兼容性。
React.createElement
React.Fragment
React.createRef
还支持回调引用,因此您可以使用以下描述进行操作,而无需使用createRef
。
const App = () => {
const callback = node => {
// ref 属性で指定した node が取得できる
console.log(node);
// do something
};
return <div ref={callback}>Now Loading...</div>
};
JSX 未使用的格式
我将省略详细说明,但可以不使用 JSX 格式来编写。
它甚至可以在不使用捆绑器、转译器等的项目中使用。
以下输出结果是等效的。
import {createElement as c, Fragment} from 'hiroshi';
const jsx1 = <div className='sample' dataSample='hoge'>TEXT</div>;
const notJsx1 = c('div', {className: 'sample', dataSample: 'hoge'}, 'TEXT');
const jsx2 = <>
{items.map(item) => <Card {...item}/>}
</>;
const notJsx2 = c(Fragment, null,
...items.map(item) => c(Card, {...item})
);
const jsx3 = <div>
<div>ITEM 1</div>
<div>ITEM 2</div>
</div>;
const notJsx3 = c('div', null, ...[
c('div', null, 'ITEM 1'),
c('div', null, 'ITEM 2'),
]);
关于未来
当前版本为0.0.x
,但根据本文的声誉,一旦测试代码和严格类型定义(TypeScript 支持)可用,版本将为1.0.x
,文档将相应扩展。我'我想
在最后
如果您发现任何错误,请打开一个问题或拉取请求。
我希望这个世界上所有的网站都像一个当红男演员的主页一样轻,在某个主页上显示出爆炸性的速度。
如果这个库可以在使网站更轻松方面发挥作用,我会很高兴。
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308623201.html