@entur/uniformen (法语)
统一版式服务的客户端库. 它从 Unforden 获取共享头,页脚和头部资产,它提供 React 组件,使其在您的应用程序中实现.
服务使布局, 更改页眉和页脚到达您的应用程序 没有新发布此软件包。 这些变动列于 服务更改日志。 。 。 .
它会做什么
Unfunden是Entur门户网站应用程序的共享头和脚印. 此软件包从 Uniforden 服务中获取 SSR 版式, 并给予您输入的数据和 React 组件以添加到您的应用程序中 .
获取的布局包含:
headerHtml– 为顶端导航提供了 HTMLfooterHtml— 为页脚提供 HTMLheadAssets——生 HTML (中文(简体) )<link>编号 :<style>标记)将添加到<head>scripts- 未加工<script>要添加的 HTML</body>csp——每个指令的CSP来源(例如:{ "style-src": [...], "script-src": [...] })合并到您页面的内容-安全政策标题中
安装
npm install @entur/uniformen
# or
bun add @entur/uniformen
该套件需要回放18或后作同级依赖.
使用量
获取布局
import { fetchUniformenLayout } from "@entur/uniformen";
const layout = await fetchUniformenLayout({
token, // the signed-in user's Auth0 access token
environment: "dev", // the Uniformen of the environment this app runs in
params: {
app: "partner",
sidebar: true,
locale: "nb-NO",
availableLocales: ["nb-NO", "en-GB"],
loginUrl: "/auth/login", // where the login link points when there is no token
logoutUrl: "/auth/logout", // where the user menu's logout row points
},
});
export default function app() {
return html`
<html lang="nb-NO">
<head>
${layout.headAssets}
</head>
<body>
${layout.headerHtml}
<main>{/* your app */}</main>
${layout.footerHtml}
${layout.scripts}
</body>
</html>
`;
将选项传递为一个对象 :
const layout = await fetchUniformenLayout({
token, // Auth0 access token; adds the user to the nav
environment: "dev", // "local" | "dev" | "staging" | "production" (default)
params: { app: "partner", sidebar: true, locale: "nb-NO" }, // query params for the SSR endpoint
timeoutMs: 1000, // how long to wait for the service (default)
});
timeoutMs (单位:千美元)number默认值 1000)是等待时间的几毫秒
服务,包括重试。 超时时,电话处理它像每一个
其他失败。 见 缓存和故障您的页面可以
而不是等待他们.
params.app 是要求布局的门户应用程序。 上行显示Entur标志旁边的应用名称. 应用程序切换器将此应用程序标记为当前应用程序,除非该应用程序未列出. 未知值使服务得到答案 400,然后调用返回 null。 。 。 .
带有参数 undefined 值不在查询字符串中。 矩阵参数为
以重复键发送( e)?key=a&key=b) (中文(简体) ).
应用程序切换器只显示给登录用户. 它链接到另一个门户
您从环境中获取了应用程序的布局。 例如,a dev
与 dev 实例的布局链接,绝不是生产.
标识旁边的环境徽章只在 Entur 中向用户显示
组织。 你不需要发送任何信息 因为服务内容
它来自你传递的标志。 其他用户看到上行没有徽章,但他们
仍然可以看到沿着顶部的彩色条纹显示页面不是生产.
何时 app 设置, 您的应用程序部署在环境的布局中
从,徽章是一个按钮。 它打开了您应用程序的链接列表
它被部署到的每一个环境。 否则,徽章是一个简单的标签.
params.sidebar (单位:千美元)boolean默认值 false)在最远处显示一个倒塌按钮
左侧的上边栏。 只有在您的应用程序有侧向导航时才设置它 。 校正让
按钮,而您的应用程序会让侧边栏。 见 边栏 详细情况.
params.simple (单位:千美元)boolean默认值 false隐藏应用程序切换器,通知,
边栏按钮和"Mine tigganger"。 顶端栏显示标志,应用程序
名称和登录链接 params.loginUrl,或者使用菜单的用户名
只有一个 params.logoutUrl 排队 它能覆盖 params.sidebar脚印
不变.
params.hideNotifications (单位:千美元)boolean默认值 false)使顶端栏没有
通知按钮,且服务不查询用户的通知.
在显示自己的通知的应用程序中使用, 因此页面没有两个
列表。 与 params.simple 设置时,按钮已被隐藏.
params.loginUrl (单位:千美元)string)是上行站点中的"洛格客栈"链接路径
改为无时 token 通过。 如果您将其删除, 则不显示登录链接 。 这一定是
一条你本源的路 绝对URL, //host 或者说 javascript: 制作
服务答案 400,然后调用返回 null。 。 。 .
params.logoutUrl (单位:千美元)string)是用户菜单点中"Logg ut"行的路径
当一个 token 通过。 如果您不显示, 则不显示登录行 。 这一定是
一条你本源的路 绝对URL, //host 或者说 javascript: 制作
服务答案 400,然后调用返回 null。 。 。 .
params.locale (BCP 47: (中文(简体) ) "nb-NO" | "nn-NO" | "en-GB"默认值 "nb-NO"这是
页眉和页脚的语言。 应用程序名称和环境标签不是
译出. 标签必须准确匹配。 譬如说, "nb" 提供服务答案
400设置 <html lang> 以同样价值计算.
params.availableLocales (单位:千美元)Locale[]) 显示一个完全带有这些语言切换器
标记,按此顺序。 如果将其删除或通过空列表,则不显示切换器 .
见 语言 用于显示和接受哪些价值观.
同样的选项适用于: fetchUniformenComponents 见下文.
反应适配器
import { fetchUniformenComponents } from "@entur/uniformen/react";
const { HeadAssets, Header, Footer, Scripts, csp } = await fetchUniformenComponents({
token,
environment: "dev",
params: { app: "partner", sidebar: true, locale: "nb-NO" },
});
export default function App() {
return (
<>
<head>
<HeadAssets />
</head>
<body>
<Header />
<main>{/* your app */}</main>
<Footer />
<Scripts />
</body>
</>
);
}
如果布局抓取失败, 所有组件都会不产生任何 csp 实值 {}。 。 。 .
适配器将布局 HTML 解析为真实的 React 元素.
csp 一样 Record<string, string[]> 那个 fetchUniformenLayout 返回,则
您只需要一个获取即可设置 Content-Security-Policy 头曰. 合并这些
输入您自己的指令.
- 地点
<HeadAssets />内部<head>。 。 。 . - 地点
<Header />内部<body>在此之前<main>。 。 。 . - 必要时,地点
<Footer />内部<body>之后<main>。 。 。 . - 地点
<Scripts />内部<body>作为最后一个元素.
与 Next.js 一起使用
与下一位.js,通过 Script 作为 loader 向 <HeadAssets> 财务报告和审定财务报表 <Scripts>。 。 。 .
否则Next.js可以改变脚本运行的顺序,因此脚本和组件的加载顺序错误.
import Script from "next/script";
// The head script sets the sidebar state before the first paint, so it must be in
// the initial HTML. The default Next.js strategy adds scripts after hydration, and
// the user would see the sidebar jump.
const BeforeInteractiveScript: typeof Script = (props) => <Script {...props} strategy="beforeInteractive" />;
<head>
<HeadAssets loader={BeforeInteractiveScript} />
</head>
<body>
<Header />
<main>{/* your app */}</main>
<Scripts loader={Script} />
</body>;
缓存和故障
fetchUniformenLayout 保留服务器程序中的内存布局。 每个
组合 environment 财务报告和审定财务报表 params 拥有自己的条目.
- 匿名布局( 无)
token)从内存中使用,只要服务Cache-Control: max-age允许。 今天是60秒钟。 之后,下一个电话 又取来. - 签入的布局包含用户名,因此在每个呼叫中都会取出. 这个 软件包将每个符号的最后一个保存一个小时,并只在 获取失败 。 它储存着一种SHA -256散列的代币,而不是代币本身.
- 如果请求失败时出现网络错误或
5xx状态, 软件包试一次 更在同一范围内timeoutMsA级4xx状态没有重审. - 如果抓取失败, 调用会返回它为相同选项获得的最后一个布局,
对于一个签名的用户来说 也一样 保存此的匿名布局
一天时间。 如果没有这样的布局, 调用返回
null。 。 。 . - 使用相同的选项打电话, 对于一个签名的用户, 同样的代号, 运行
同时,向Unixen提出一个请求。 一个加入运行的电话
请求还使用该请求的
timeoutMs。 。 。 . - 内存最多持有100个匿名和100个签入版式. 当其中之一 它们是完整的,最近使用的布局被删除。 过期布局 每次存储新的布局都会被移除,所以签入的布局很快就消失了 时间过后,即使用户不回来.
- 你得到的每个布局都是你自己的复制件,所以你可以将自己的来源添加到
layout.csp不更改缓存布局.
要立即获取新布局, 例如在 unifen 部署后, 呼叫
clearUniformenLayoutCache()。 。 。 .
每个请求都发出一个 X-Uniformen-Client 带有软件包名称和
例如,版本 @entur/[email protected]。服务使用它来查看
版本正在使用中.
边栏
过 params.sidebar: true 显示顶端最左边的倒塌按钮
栏。 unifen不使侧边栏本身.
状态只存储于根元素上的此属性 :
<html data-uniformen-sidebar="expanded | collapsed"></html>
侧边栏代码在 headAssets这样 <HeadAssets /> 必须是在 <head>。
在第一次涂料之前设置存储状态, 因此崩溃的侧边栏不会跳出 .
它也开始在您自己的脚本运行前观看属性,所以它可以看到每个
写到属性,甚至早期.
基于属性的侧边栏样式 . 那么你不需要JavaScript状态, 而侧边栏在第一个相框上是正确的. 这在服务器上也能操作 应用程序,如果服务器不知道用户的偏好:
:root[data-uniformen-sidebar="collapsed"] .my-sidebar {
width: 0;
/* Also hide it from screen readers and the tab order. With only width: 0, the
links can still get focus and screen readers still read them. */
visibility: hidden;
}
如果崩溃是动画, 请在 visibility 一、导 言
宽度( n)transition: width 150ms ease, visibility 150ms ease) (中文(简体) ). 那内容就留下
在动画完成前可见 .
如果你的侧边栏 在一个阴影根 :root[…] 选择器无法到达 .
在根上设置自定义属性 。 自定义属性继承到
阴影根,所以里面的样式可以使用值:
:root {
--my-sidebar-width: 240px;
}
:root[data-uniformen-sidebar="collapsed"] {
--my-sidebar-width: 0px;
}
要使用不同的默认时 <html data-uniformen-sidebar="collapsed"> 打开
服务器。 校正只写用户存储的属性
偏好,或者当属性没有设置时,所以您的值被保留.
Unifen 将您提供的值作为起始状态,而不是改变。 没错
未保存到 localStorage,没有 uniformen:sidebar 事件为它起火。 当
用户第一次崩溃或扩展侧边栏,该选择 实值 已经保存,
从那时起,它就被使用,而不是你所作的默认。 如果你的应用商店
服务器上的首选项,并想要使用它自己的值,清除
uniformen:sidebar 当它保存自己的副本时键.
把它从其他地方砸倒,例如边栏中的关闭按钮,a 键盘快捷键或路由更改,写出相同的属性。 上行按钮 执行相同的:
document.documentElement.dataset.uniformenSidebar = "collapsed";
对脚本变化的反应听到这个事件。 当您使用上面的 CSS 时 能够。 从按钮或你的应用软件中, 事件会引发任何变化, 并拥有 新状态 :
window.addEventListener("uniformen:sidebar", (event) => {
setCollapsed(event.detail.collapsed);
});
如果一个组件需要JavaScript中的状态,例如边栏组件
带有 collapsed 道克,读取属性并观看. A 类 MutationObserver 看见了
每写到属性。 与事件不同的是,它也在一个网页上工作
校正头脚本缺失, 例如布局抓取失败 。 礛
您的侧边栏和顶边栏一样工作。 在反应中 :
import { useCallback, useSyncExternalStore } from "react";
const ATTRIBUTE = "data-uniformen-sidebar";
const root = () => document.documentElement;
function subscribe(onChange: () => void) {
const observer = new MutationObserver(onChange);
observer.observe(root(), { attributeFilter: [ATTRIBUTE] });
return () => observer.disconnect();
}
export function useSidebarCollapsed() {
const collapsed = useSyncExternalStore(
subscribe,
() => root().getAttribute(ATTRIBUTE) === "collapsed",
// The server does not know the user's preference.
() => false,
);
const setCollapsed = useCallback((next: boolean) => {
root().setAttribute(ATTRIBUTE, next ? "collapsed" : "expanded");
}, []);
return [collapsed, setCollapsed] as const;
}
在服务器发送的应用程序中,服务器会使扩展的侧边栏. 如果用户 偏好崩溃,水合后侧边栏会改变,用户会看到 跳下来。 CSS方法没有这个问题, 所以把它用于所有 CSS可以做到这一点。 在一个仅在浏览器中制作的单页应用程序中,状态是 从第一个角度来说是正确的.
event.detail 输入。 这个事件和 uniformen:locale 于
WindowEventMap,因此,在一个从软件包中导入的项目中,每个文件都得到
输入时没有额外输入或显示.
校正从属性中更新其余:
按钮,其 aria-expanded,以及它保存的偏好 localStorage 下级
uniformen:sidebar。 。 。 .
语言
params.locale 是服务所提供语言.
params.availableLocales 添加用户可以更改语言的控制 :
const layout = await fetchUniformenLayout({
token,
params: { app: "partner", locale, availableLocales: ["nb-NO", "en-GB"] },
});
这些语言是一组广播节目。 服务器使 locale 作为
选中一个, 因此没有客户端状态, 标签从开始就是正确的 .
每个语言都以自己的语言来命名("Norsk bokmål","英语"). 控制权
总是被贴上"Språk / Language"的标签,不管是什么 locale 是,所以用户可以找到它
即使他们不能读取当前语言.
显示控件的地方取决于上行. 它只显示在一个 地点 :
- 当一个用户被签入时,它是用户菜单中的"Språk / Language"一栏,
在登录行上方。 它呆在那里,当
params.simple已经设定. - 在无菜单的匿名上行是左侧的单独控制
输入链接。 它显示一个地球和当前语言。 在小屏幕上
文字是隐藏的,地球表有一个
aria-label与语言名称.
只列出您自己的应用程序的标签 。 制服支持三个,但
提供您页面所没有的语言比不提供更糟糕。 你选择
命令。 命令。 如果列表有重复的标签, 未知的标签或不包含
locale,服务答案 400 调用返回 null。 。 。 .
您的应用程序必须处理选择. 当用户选择语言时, 顶端栏
发送一个事件,而无所作为。 它没有设置饼干,写给
localStorage,重新装入或更改栏中的标签:
import { writeLocaleCookie } from "@entur/uniformen";
// The tags your app is translated into. Send them as `params.availableLocales`.
const SUPPORTED = ["nb-NO", "en-GB"] as const;
window.addEventListener("uniformen:locale", (event) => {
writeLocaleCookie(event.detail.locale);
window.location.reload();
});
重装会改变语言. 服务器使信头使用一种语言, ,模块装入时会加载自己的文本。 如果顶部栏变了 没有重新装入的标签,其余的页面仍将使用旧语言.
如果用户选择已经显示的语言,则没有发送事件,所以 页面不重新装入.
选择服务器上的语言
在下一次渲染时,将存储的选择发送为 params.locale 设置 <html lang>
以同样价值计算. readLocaleCookie 财务报告和审定财务报表 resolveLocale 用简单的绳子,所以他们
与任何服务器框架一起工作:
import { fetchUniformenLayout, readLocaleCookie, resolveLocale } from "@entur/uniformen";
const SUPPORTED = ["nb-NO", "en-GB"] as const;
const locale = resolveLocale({
chosen: readLocaleCookie(request.headers.get("cookie")),
acceptLanguage: request.headers.get("accept-language"),
supported: SUPPORTED,
fallback: "nb-NO",
});
const layout = await fetchUniformenLayout({
token,
params: { app: "partner", locale, availableLocales: [...SUPPORTED] },
});
// Render <html lang={locale}> with the layout.
resolveLocale 使用您的应用程序所支持的第一个 :
chosen,用户选择的语言。 您的应用程序不支持的值是 忽略, 因此旧的或已更改的饼干无法打破页面 .- 语文
acceptLanguage,按其分类q数值。 标记为q=0财务报告和审定财务报表*被排除在外. fallback。 。 。 .
当标签是同一标记时, 或当其语言部分时, 标签匹配
匹配 : en-US 给 en-GB,以及 nb 财务报告和审定财务报表 no 给 nb-NO。浏览器经常发送
仅这些短或区域标记,所以仅一个精确的匹配就会错过许多用户.
返回类型是您的类型 supported 列表,因此可以使用结果
您的应用程序期望它自己的语言类型.
在浏览器中使用相同的功能 如果你自己的文本选择他们的语言
在这里。 过 navigator.languages,按其自身顺序使用。 浏览器
正在建设 Accept-Language 从同一个列表,所以页面和页眉得到
同样的语言,同样在饼干设定前的第一次访问中:
const locale = resolveLocale({
chosen: readLocaleCookie(document.cookie),
acceptLanguage: navigator.languages,
supported: SUPPORTED,
fallback: "nb-NO",
});
这个 entur_locale 饼干
writeLocaleCookie 写入 entur_locale 饼干LOCALE_COOKIE整个
为期一年 SameSite=Lax,并与 Secure 关于HTTPS。 只有你的应用
读它。 制服服务没有。 使用此名称可以让 Entur 应用程序全部存储
同样的选择.
默认饼干属于设定它的主机. 过 domain,例如
writeLocaleCookie(locale, { domain: "entur.org" }),与其他选择分享
应用程序在同一域. 某个域上的所有应用程序都必须这样做. 如果一个应用
将饼干设定为 domain 和另一个没有,浏览器发送两个饼干与
同样的名字, 和它们之间的顺序是不可靠的. readLocaleCookie 返回时
第一个. domain 必须是页面的主机或它的母机,所以无法工作
打开 localhost。在另一个域中,浏览器忽略了 cookie 没有出错.
如果您将应用程序从主机饼干移动到 domain,删除旧主机
在你写新书之前先吃饼干:
document.cookie = "entur_locale=; path=/; max-age=0"。 。 。 .
项目结构
packages/uniformen/
├── src/
│ ├── index.ts # Public API: fetchUniformenLayout, the locale helpers and the types
│ ├── types.ts # UniformenLayout type definition
│ ├── index.test.ts # Tests for fetchUniformenLayout
│ ├── locale.test.ts # Tests for the locale helpers
│ ├── reactAdapter.tsx # React adapter: fetchUniformenComponents
│ ├── version.ts # Package version, updated by release-please
│ └── lib/
│ ├── fetchUniformenLayout.ts # Fetches layout from the Uniformen SSR endpoint
│ ├── locale.ts # Locale cookie and resolveLocale
│ └── layoutCache.ts # In-memory cache of fetched layouts
├── dist/ # Compiled output (generated by bun run build)
├── tsconfig.json # TypeScript config for type checking and local dev
├── tsconfig.build.json # TypeScript config for emitting .d.ts declaration files
└── package.json
大楼
bun run build
出版
释放 - 请创建所有释放。 不要用手释放: 不要运行
bun publish 或者说 npm publish ,不编辑 version 内 package.json
或者说 变动情况。 。 。 .
每一次推进 main,请释放 - 请收集更改的承诺
packages/uniformen/。它使下个版本的释放拉动请求打开
生成的更改日志 。 合并后,释放被标记
发布工作流程 建造、测试和出版
@entur/uniformen {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}请说.
该版本基于承诺主题,所以它们必须使用 常规武器委员会数字 :
feat(uniformen): add loginUrl to the render options
| 类型 | 对已公布版本的影响 |
|---|---|
feat | 轻微起落 |
fix | 补丁凸起 |
feat!,或带有 BREAKING CHANGE: 页脚 | 重大冲击 |
chore, (中文(简体) ), docs, (中文(简体) ), refactor, (中文(简体) ), test, (中文(简体) ), build, (中文(简体) ), ci | 无释放 |
见 捐款额 完全承诺和释放规则.