-
Notifications
You must be signed in to change notification settings - Fork 24
前端框架配置约定
页可视化搭建框架 pipeline 实现了编辑器和页面前端框架的分离, 支持任意前端框架页面的可视化搭建.
使用 pipeline 实现页面可视化搭建时, 并不需要切换原有业务的前端框架, 只需要对页面前端框架的组件写法, 文件目录和构建脚本做一些约束和改造, 就可以复用该前端框架现有的技术组件和业务组件, 实现可视化搭建.
这篇教程主要介绍 pipeline 对前端框架的约定, 并以 react 为例, 介绍前端框架改造后的代码结构和构建脚本的约定.
总体目录, 后续会详细介绍.
.
├── README.md
├── scripts // 项目构建脚本
│ ├── build-server.js // pipeline 打包
│ ├── build.js // 常规的项目 prod 打包
│ ├── server-check-schema.js // pipeline 配置数据校验
│ ├── server-copy-config.js // pipeline 配置文件拷贝
│ ├── server-generate-library-info.js // 生成 pipeline 组件库信息
│ ├── server-template-archive.js // 生成 pipeline 页面模板压缩包
│ ├── utils-schema-validator.js // 页面和组件的 JSON Schema 校验器
│ └── start.js // 本地开发构建
├── config
│ ├── index.js // 页面全局替换字段配置
│ └── webpack.xxx.js // webpack 配置
├── pipeline-template.zip // 生成的 pipeline 压缩文件
├── server // pipeline 后台渲染工作目录
│ ├── config // 组件配置信息
│ ├── dist // pipeline 打包后的页面
│ ├── node.js // 页面后台渲染脚本
│ └── preview-inserted-script.js // 预览模式的嵌入脚本
└── src
└── config // 页面和组件的配置信息
├── base-config-schema.json // 页面全局配置约束文件
├── base-config.json // 页面全局配置
└── components.json // 组件列表描述文件
$ npm run start # 本地开发构建
$ npm run build # prod 模式构建, 构建出可发布页面
$ npm run server # pipeline 后台构建
$ npm run render # 后台构建后本地验证渲染结果
$ npm run template # 打包页面资源用于上传到 pipeline 后台服务器
pipeline 已经提供了几大主流前端框架的模板, 可以参考熟悉的框架模板来看这个教程:
pipeline 页面可视化编辑其实是对页面各组件的可视化编辑. 为了实现组件的可视化编辑, 需要提供配置表单给用户填入配置数据, 并将配置数据传给组件.
约定组件目录为 src/components
, 其中每个子目录为一个页面组件.
组件路径示例:
./src/components
├── pipeline-gap-demo // 间隔区组件
├── pipeline-header-demo // 头部组件
├── pipeline-info-demo // 信息组件
└── pipeline-weather-demo // 天气组件
头部组件文件示例:
./pipeline-header-demo
├── config // 组件配置字段声明目录
│ ├── data.json // 组件默认配置字段
│ └── schema.js // 组件配置字段的 Schema 声明
├── index.js // 组件源码
├── style.less
└── package.json // 组件描述文件
页面组件的目录下有几个特定文件,
其中 config/data.json
, config/schema.js
和 config/package.json
为 pipeline 约定了名称和格式的文件.
组件实例可以查看这里: pipeline-header-demo.
是组件的默认配置数据, 其内容是组件添加到页面时填入的默认配置数据. 示例:
{
"title": "页面可视化搭建框架",
"src": "https://avatars3.githubusercontent.com/u/38666040",
"link": "https://github.com/page-pipepline"
}
为组件配置数据的 JSON Schema, 用于编辑时自动生成组件配置表单. 示例:
module.exports = {
title: '头部区',
type: 'object',
properties: {
title: {
title: '头部标题',
type: 'string',
default: '头部标题',
},
src: {
title: '头部图片',
description: '试试输入新的图片URL: https://vuejs.org/images/logo.png',
type: 'string',
default: '头部图片'
},
link: {
title: '头部图片点击跳转',
type: 'string',
format: 'url',
default: '头部图片点击跳转',
}
}
};
其具体写法可以参考: JSON Schema Demo.
组件描述文件, 包含组件英文名称, 组件中文名称等. 示例:
{
"pipeline": {
"name": "pipeline-header-demo",
"title": "头部区示例",
}
}
组件目录中的 index.js
/index.vue
为组件源码, 各个前端框架有不同的组件语法, 但都需遵循 pipeline 的组件属性(Props)约定, 见下一节.
组件的配置数据通过组件属性传入组件中, 配置数据名称约定为 props.config
, 数据类型为 object
. props.config
对象的字段与 config/schema.js
的声明一致, 其默认数据为 config/data.json
.
在组件中使用 props.config
作为组件渲染和组件逻辑的常量.
下图展示了头部组件(pipeline-header-demo)的 props.config
用法. 其中 props.config.title
和 props.config.src
用于组件模板, 并渲染到 View 上; props.config.link
作为点击交互的跳转链接, 用于动态逻辑中.
组件属性的使用实例可以查看这里: pipeline-header-demo.
除了传入 config
到组件中, 还需要通过 props 传入另外2个组件信息: data-component-id
和 data-component-name
, 用于可视化编辑器唯一标识组件, 实现编辑组件器切换和预览页面滚动.
给组件传入3个属性的方式如下图所示:
并且需将 data-component-id
和 data-component-name
添加为组件根 HTML 元素的自定义属性.
添加方式如下图所示:
添加到组件根 HTML 元素的渲染结果:
组件列表声明文件
声明了页面使用的组件列表, 包含组件名称
, 组件id
, 组件配置数据
等.
pipeline 使用组件列表声明文件和动态组件生成页面, 所以只要修改组件列表声明文件, 就能得到新的页面:
组件列表声明文件约定路径为 src/config/components.json
. 组件列表声明文件示例如下图所示.
其中 id
表示组件id, name
表示组件名称, data
表示组件属性(Props), data
会注入到组件的 Props.config
中.
pipeline 使用不嵌套的组件排列方式, 所以组件声明文件其实是一个数组对象.
组件列表声明文件实例可以查看这里: compenents.json
在页面入口引用组件声明文件, 并且根据组件声明文件进行页面组件的渲染.
如 react 的渲染示例代码:
import mycomponents from './config/components'; // 引入组件声明文件
// 组件声明优先从全局对象上取
const pipelineComponents = (typeof window !== 'undefined') ?
window.INIT_DATA || mycomponents : mycomponents;
// 页面中的组件类
const components: {
'pipeline-gap-demo': PipelineGapDemo,
'pipeline-info-demo': PipelineInfoDemo,
'pipeline-header-demo': PipelineHeaderDemo,
'pipeline-weather-demo': PipelineWeatherDemo,
},
// 根据组件声明实例化组件
const Components = pipelineComponents.map(oneComponent => {
const OneComponent = components[oneComponent.name];
return OneComponent && (
<OneComponent
key={oneComponent.id}
data-component-id={oneComponent.id}
data-component-name={oneComponent.name}
config={oneComponent.data}/>);
});
// 渲染页面组件
return (
<div className="App">
{Components}
</div>
);
其中的关键逻辑是: 组件列表声明优先从全局对象中取, pipeline 做后台渲染时, 会将可视化编辑后的组件列表声明插入到页面的全局对象中. 这点和服务端渲染(SSR)将请求后台获取的数据插入到页面全局对象的做法很相似. 注入的全局对象名称为 window.INIT_DATA
.
页面全局配置是指超出各个组件配置范围, 应用在整个页面内容和样式的配置. 页面全局配置的使用方式是通过 html-webpack-plugin 将配置字符串插入到页面 html 模板.
添加页面全局默认配置 src/config/base-config.json
和配置约束src/config/base-config-schema.json
.
-
src/config/base-config.json
的配置数据会在本地调试和生产打包时替换到页面 html 模板中. 在 pipeline 后台打包时,会将配置数据占位符插入页面, 后台渲染时将配置数据替换掉占位符, 实现配置数据修改. -
src/config/base-config-schema.json
是配置数据的 JSON Schema, 用于在页面上自动生成页面全局配置的配置表单.
这2个文件的写法可以参考: pipeline-template-react-config.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title><%= htmlWebpackPlugin.options.title %></title>
<style type="text/css">
html, body {
background-color: <%= htmlWebpackPlugin.options.backgroundColor %>
}
</style>
</head>
<body>
<%= htmlWebpackPlugin.options.reactInstancePlaceholder %>
</body>
</html>
其中的 htmlWebpackPlugin.options.backgroundColor
, htmlWebpackPlugin.options.reactInstancePlaceholder
为待替换的配置字符. <% ... %>
为 html-webpack-plugin
的占位符规则.
可参考实例: html-template.
在 config/index.js
中引入页面全局默认配置文件 src/config/base-config.json
, 并转换为开发模式和 pipeline 后台模式需要的替换对象.
参考实例: config/index.js.
// 引入页面全局默认配置文件
const baseConfig = require('../src/config/base-config.json');
// 开发模式和生产打包时将配置数据各个字段替换为对应的默认数据
const HWPPageBaseConfig = Object.keys(baseConfig).reduce((accumulator, key) => {
accumulator[key] = baseConfig[key];
return accumulator;
}, {});
// pipeline 后台打包时将配置数据各个字段替换为配置数据占位符
const HWPPageBaseConfigForServer = Object.keys(baseConfig).reduce((accumulator, key) => {
accumulator[key] = `<!--baseConfig-${key}-->`;
return accumulator;
}, {});
// 各个构建模式的页面全局配置替换对象
module.exports = {
build: {
HWPPageBaseConfig
},
dev: {
HWPPageBaseConfig
},
server: {
HWPPageBaseConfigForServer,
},
};
- 开发模式和生产模式的打包, 需要得到目标页面, 此时的页面全局配置数据直接替换到页面模板中.
- pipeline 后台打包模式, 页面全局配置占位符是转换为另外一种格式的占位符(格式:
<!--baseConfig-${key}-->
), 然后在页面可视化编辑时根据用户修改的数据, 对<!--baseConfig-${key}-->
做替换, 替换为用户配置的数据.
然后给 htmlWebpackPlugin
添加模板内容替换的参数. 需要给开发模式, 生产模式和 pipeline 构建模式都添加对应的 htmlWebpackPlugin
参数.
config/webpack.config.dev.js
中的添加示例如下:
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
inject: true,
chunks: [item],
template: paths.appHtml,
filename: item + '.html',
// 添加模板内容替换的参数
...config.dev.HWPPageBaseConfig
}));
可参考实例: webpack.config.dev.js.
页面模板已有了本地开发(dev
)和生产构建(prod
)的打包方式, 需要添加 pipeline 后台需要的打包模式 -- server
.
pipeline 后台使用的目录为 server
. 需要先新建 server
目录.
server 目录中的文件如下:
./
├── config // 打包生成的组件配置文件和页面配置文件
├── dist // pipeline 后台打包的结果目录
├── node.js // pipeline 后台渲染脚本
└── preview-inserted-script.js // 编辑器插入到预览页面的脚本, 用于编辑器获取页面状态
在 server
打包模式中, 会将页面打包到 server/dist
, 将组件配置和页面配置相关的文件打包到 server/config
. 这两个目录是构建生成的, 不需要手动添加.
node.js
是后台渲染脚本, 会将用户编辑的配置内容插入到页面, 并且重新打包页面.
preview-inserted-script.js
在可视化编辑模式下插入到页面中, 监听页面收到的 poseMessage
事件, 实现页面自动滚动到当前编辑的组件处.
在构建目录 scripts
中添加4个构建脚本, 4个脚本名称和用处如下:
server-check-schema.js // 校验各组件配置字段和其 Schema 是否匹配, 页面全局配置和其 Schema 是否匹配
server-copy-config.js // 将 src/config 下的组件声明文件和页面全局配置等 copy 到后台打包目录
server-generate-library-info.js // 收集和生成组件库中组件的描述信息、默认配置数据和配置约束
utils-schema-validator.js // JSON Schema 校验函数, server-check-schema.js 中使用
这几个脚本是遵循 pipeline 约定的文件, 直接从已支持框架的页面源码中复制就可以了. 参考示例: scripts.
复制 prod 构建 webpack 配置 config/webpack.config.prod.js
到 config/webpack.server.config.prod.js
, 作为 server
构建的配置文件, 再做少量修改.
src/config/components.json
为组件列表声明文件, 后台打包时组件列表声明文件是直接插入到页面中的, 所以不需要在构建时候引入.
module.exports = {
...
externals: {
'./config/components': {
commonjs2: '../config/components.json',
commonjs: '../config/components.json',
},
},
...
src/config/components.json
会通过 window 全局变量(window.INIT_DATA
)注入, 在页面渲染时优先从全局变量上取.
// 组件声明优先从全局对象上取
const pipelineComponents = (typeof window !== 'undefined') ?
window.INIT_DATA || mycomponents : mycomponents;
修改输出目录为 pipeline 后台需目录 server/dist
// config/paths.js: appBuildServer: resolveApp('server/dist'),
output: {
...
path: paths.appBuildServer,
...
页面全局配置在 pipeline 后台渲染中会替换为用户编辑的字段. 源码页面中的 <%= htmlWebpackPlugin.options.xxx %>
占位符, 替换为 <!--baseConfig-xxx-->
; pipeline 后台渲染再将 <!--baseConfig-xxx-->
替换为用户编辑的页面全局字段.
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
...
...config.server.HWPPageBaseConfigForServer,
...
}))
在 package.json 中添加 server 打包脚本:
"server": "rm -rf server/dist && rm -rf server/config && node scripts/build-server.js"
可视化编辑后的组件列表和组件配置存储到后台的 server/config/components.json
文件中; 页面全局配置存储到 server/config/base-config.json
中.
pipeline 的后台渲染原理非常简单:
- 将
components.json
插入到index.html
中作为全局变量. - 将
base-config.json
中的字段值插入到index.html
.
后台渲染脚本为 server/node.js
, 其会读取 components.json
和 base-config.json
, 并将需要的数据插入到 index.html
中.
具体实例可以参考: node.js
本地测试后台渲染是否可用指令:
$ npm run render
server
打包脚本生成的资源文件, 要作为页面模板上传到 pipeline 后台, 需要对文件夹进行压缩打包. 同时 pipeline 对目录结构有要求, 通过压缩脚本可以规范化压缩操作.
压缩脚本在 scripts/server-template-archive.js
中, 使用 archive
node 压缩库进行资源的压缩.
压缩脚本:
$ npm run archive
压缩结果约定为 pipeline-template.zip
, 所在目录为工程根目录.
server-template-archive.js
文件的压缩功能可以直接复制其他框架中的相同文件. 参考示例: server-template-archive.
其中差异点在于添加要打包的目录和文件.
压缩打包是给 pipeline 后台使用, 可以忽略的目录有: node_modules
(依赖包), dist/build
(prod模式生产构建输出目录), pipeline-template.zip
(压缩包本身)等.
需要打包的目录参考:
// 需要打包的目录
const directoryList = [
'scripts',
'config',
'server',
'src'
];
// 需要打包文件
const fileList = [
'.babelrc',
'.editorconfig',
'.eslintignore',
'.eslintrc.js',
'.postcssrc.js',
'package.json',
'README.md',
];