停止使用 ejs 和 pug 并使用 tsx 编写 html?
介绍
这是一个html模板选择的故事。
对于不叫Modern Front的项目,我们还是使用ejs、pug等html模板引擎库来编写和交付html。
这一次,我们说的是采用 tsx 作为这样的模板引擎。
结论
将renderToStaticMarkup
中的tsx文件(react-dom
的函数)转换成字符串,输出为html文件。这使得使用 tsx 表示法生成 html可以做。
下面是一个使用 webpack 自动编译的示例。
ejs 和 pug 的局限性
ejs和pug可以用html来描述JavaScript,可以用if, for, switch, try/catch
等js语法,用let, const
进行变量声明,用include
进行部分文件的提取和读取,可以高效处理html。
但是,随着项目(以下简称 PJ)的发展,您可能会感到各种限制。
- 无法进行 lint 检查(如果你寻找它,可能有IDE扩展)
- 未键入
include
的参数 - 在编译之前我不知道错误&失败时难以识别错误位置
- 限制你的感觉
为了解决上面的问题,我想介绍一下 React 的语法 tsx 作为 html 模板引擎。
tsx 的优势
tsx 首先是什么?
jsx 是 JavaScript 语法的扩展,是用 TypeScript 编写的。
这里是对jsx的详细解释。
与 ejs 能够在 html 中编写 JavaScript 的形象相比,jsx 就像能够在 JavaScript 中编写 HTML。
使用 tsx 可以解决 ejs 和 pug 的局限性
作为前提,上面出现的所有ejs和pug函数if, for, const, include
都可以用tsx实现。
最重要的是,您可以解决使用 ejs 和 pug 时遇到的问题。
- 无法检查 lint 的问题
- 已解决,因为 eslint 按原样运行。
include
参数未输入- 由于参数作为
props
传递给部分文件,这是 tsx (/jsx) 的函数,因此可以使用静态类型。
- 由于参数作为
- 难以理解错误位置
- Eslint 运行,所以在编码时解决
另一个优点是学习成本很低,因为您没有创建 React 应用程序。
简单地记住 jsx 语法(if
是单行,for
是 map
等)与学习 ejs 和 pug 语法没有太大区别。
如何将 tsx 转换为 html
我们来看看具体的实现。
首先,使用ReactDOMServer
对象的renderToStaticMarkup
方法作为将tsx转换为html的方法。
tsx 被 React 转换为 JavaScript 一次,但是可以通过上面的函数在 Node 服务器上转换为静态的 html 字符串。
我将介绍两种方法,一种使用 webpack,一种不使用。
1.没有webpack的方法
首先,我们将了解如何使用ts-node
简单地编译 tsx,而不使用 webpack 并输出 html。
你需要的包
yarn add -D @types/node @types/react @types/react-dom react react-dom ts-node typescript
适当准备tsconfig.json
(需要设置"jsx": "react-jsx"
),准备以下文件。
页面.tsx
import ReactDOMServer from "react-dom/server";
const App = () => {
return (
<div>
<h1>App Page.</h1>
<p>description.</p>
</div>
);
};
const pageString = ReactDOMServer.renderToString(<App />);
const page = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
</head>
<body>
${pageString}
</body>
</html>
`;
console.log(page);
export default page;
执行以下命令会将字符串化的 html 输出到控制台。
我看到你可以从 tsx 生成 html 字符串。
$ ts-node page.tsx
您所要做的就是根据这个字符串生成一个 html 文件。
我认为使用 Node.js 函数的方法有很多,但以下是一个示例。
索引.ts
import fs from "fs";
import path from "path";
import page from "./page";
const writeFile = async (file: string, data: string): Promise<void> => {
await fs.promises.mkdir(path.dirname(file), { recursive: true });
fs.promises.writeFile(file, data);
};
const filename = path.basename(__filename, ".ts");
writeFile(path.resolve(__dirname, `build/${filename}.html`), page);
build/index.html
在我运行时被喷出。
$ ts-node index.ts
我能够使用 tsx 作为模板引擎!
2.如何使用webpack
嗯,我发现用上面的方法可以从tsx生成html。但是,当必要页面的数量增加时,它似乎有点麻烦。
那么让我们使用 webpack 搭建一个自动编译环境。
(那些说不需要 webpack 的人之后就不需要了。)
首先安装所需的软件包。
$ yarn add -D @types/react @types/react-dom esbuild-loader globule html-webpack-plugin html-webpack-skip-assets-plugin prettier react react-dom@17.0.2 typescript webpack webpack-cli webpack-dev-server
※笔记※
react-dom
库的最新版本是 2005 年 10 月 22 日的 ver.18,但由于某种原因,当它是 ver.18 时,它无法编译并出现错误 Error: TextEncoder is not defined
。 (如果你知道为什么,请...)
所以我安装了ver.17。
使用export
html 字符串(如page.tsx
和HtmlWebpackPlugin
)对tsx 文件进行grep,以自动将其编译为html 文件。
我将编写一个脚本,以便即使屏幕数量像 MPA 一样增加,也可以完成 grep。我将globule
库用于grep。
webpack.config.js
const path = require('path');
const globule = require('globule');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {HtmlWebpackSkipAssetsPlugin} = require('html-webpack-skip-assets-plugin');
const assignPlugins = (env) => {
const globuleFiles = ['**/*.tsx', '!**/_*.tsx', '!**/_partials/**/*.tsx'];
/** 指定されたディレクトリからgrepしたtsxファイル */
const templateFiles = globule.find([...globuleFiles], {cwd: `${__dirname}/src/pages`});
/** entryファイルを格納したオブジェクトを作成 */
const entriesList = templateFiles.reduce((temp, current) => {
temp[`${current.replace(new RegExp(`.tsx`, 'i'), `.html`)}`] = `${__dirname}/src/pages/${current}`;
return temp;
}, {});
const assignObject = { plugins: [] };
for (const [htmlFileName, tempFileName] of Object.entries(entriesList)) {
assignObject.plugins.push(new HtmlWebpackPlugin({
filename: htmlFileName,
template: tempFileName
}));
env.WEBPACK_BUILD && assignObject.plugins.push(new HtmlWebpackSkipAssetsPlugin({ excludeAssets: [/entry.js/] }));
}
return assignObject;
};
module.exports = (env) => (
Object.assign({
entry: './src/entry',
output: {
path: path.join(__dirname, 'dist'),
filename: 'entry.js'
},
devtool: false,
watchOptions: {
ignored: /node_modules/
},
resolve: {
extensions: ['.js', '.ts', '.tsx'],
},
module: {
rules: [
{
test: /.tsx$/,
use: [
{
loader: 'esbuild-loader',
options: {
loader: 'tsx',
}
}
]
},
],
},
devServer: {
...
watchFiles: [
'src/**/*.tsx'
],
},
}, assignPlugins(env));
);
需要准备入口文件,所以直接在src目录下准备entry.js
。
积分
- 入口文件
entry.js
会在构建时自动从html 中的script
元素中读取,但它是不必要的文件,因此不会输出HtmlWebpackSkipAssetsPlugin
。但是,在开发过程中,除非读取这个入口文件,否则它不会被编译,所以这个插件只有在
env.WEBPACK_BUILD
是true
时才会被读取(构建时)。 - 为
devServer.watchFiles
选项指定'src/**/*.tsx'
以根据 tsx 文件的变化使 webpack-dev-server 热重载。
▼ 这里是刚刚吐出html的最小环境
奖金
由于自己搭建了webpack环境,所以尝试创建一个可以同时编译sass和typescript的环境。
yarn start
将启动本地服务器,yarn build
将在 dist
目录下构建它。
好像每个项目都需要设置图片压缩,所以一次都没放。
[额外奖励] 从 html 到 tsx 的转换
在将现有的 html 文件转换为 tsx 以进行增强等并对其进行开发时,有必要的过程,例如重写和转义反引号,我觉得手动操作很麻烦/辛苦,所以我用脚本将它自动化。我是被允许。
在pages
目录下新建一个转换前的html文件,执行以下命令生成同名的tsx文件。 (html文件被删除)
$ node convertHtmlToTsx.js
由于有新文件差异的文件是用 git 一次性转换的,所以可以同时转换多个文件。
源代码是这里是。
概括
我尝试使用 tsx 作为 html 模板引擎构建环境。
最近SPA、SSR、SSG已经成为主流,webpack本身也在消亡,但我觉得还是有项目交付静态html的。
如果我能为改善某人的开发体验做出贡献,我会很高兴。
参考文章
本文用作创建存储库的参考。谢谢你。
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308628452.html