将使用Angular开发的应用程序嵌入到Confluence中,而无需使用插件
尽管我们试图通过将JavaScript嵌入HTML宏和用户宏来实现在Confluence中不存在的功能,但我们发现存在一个小障碍。使用HTML宏存在用户在编辑页面时可能触及到的风险,而用户宏会导致Velocity模板引擎解析JavaScript时出现错误,因此需要对将JavaScript发送给用户的方式进行改进。
尽管在用户宏中可以使用$generalUtil.escapeForJavascript(String s)方法来对Javascript进行转义,但是要先对Webpack处理后的Javascript进行转义并插入参数,这样会增加一些负担和服务器开销。(参考:GeneralUtil类)
所以,可以使用Confluence提供的静态文件功能,在不给服务器带来压力的情况下,在Confluence上设置提供使用Angular等开发的应用程序的方式。以下介绍两种向用户提供的方法。这种方法不仅适用于Angular,而且应该适用于任何JavaScript应用程序。
-
- Confluenceと関係なくAngularを表示する
- Confluenceのページ内にAngularを埋め込む(ユーザの書いたページの内容を操作するのに使える)
完成想象
提供静态文件需要
按照Confluence的官方文档中的描述,“如何使用Confluence提供静态内容”,如果将文件放置在/confluence目录下,例如myfile.html,在浏览器中可以通过/myfile.html进行访问。
: Confluenceのインストールディレクトリ
: ConfluenceのベースURL。「ConfluenceとJiraをnode.jsで作った簡易プロキシの後ろで動かす」で書いたように変えられる)
无论是否与Confluence有关,显示Angular。
因为Angular的index.html无法直接使用,所以需要按照下方的”index.html的更改”来确保能够正确引用所需的文件。在修改后,将使用ng build编译的文件复制到用于提供静态文件的文件夹中,就可以打开了。
index.html文件的修改
由於Angular項目無法直接使用,所以需要按照以下方式修改index.html文件。
-
- 为了解决CONFSERVER-53166 bug,我们需要添加一个指定装饰器的标签。如果没有这个标签,页面将无法显示,所以请注意content必须不是none。
将更改为。Angular默认以根目录为基准,所以如果不进行这个设置,脚本将无法正确加载。
<!doctype html>
<html lang="ja">
<head>
<!-- [1] バグ対策 -->
<meta name="decorator" content="none"/>
<!-- [2] スクリプト等を相対参照するのに必要 -->
<base href=".">
<meta charset="utf-8">
<title>Sample</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
将内容复制到confluence文件夹中。
当修改了index.html后,使用ng build或ng build –aot进行构建。默认情况下,构建结果会生成在dist/<项目名称>目录下的文件中。将这个文件复制到Confluence的存放静态文件的文件夹confluence中即可。
不能省略index.html文件。如果省略,将显示Confluence的主页。
这种方法简单方便,但需要注意的是,可以在没有Confluence登录的情况下进行浏览。
我在我的电脑上尝试了一下,发现通过Confluence进行显示比起ng serve时非常慢。我不太明白为什么加载Javascript要花费接近20秒的时间。如果直接打开Javascript只需要一瞬间,为什么会有这么大的差距呢?有没有进行某种后台检查?
将Angular嵌入到Confluence页面中
可以通过在Confluence页面中放置元素,并添加必要的脚本和样式表加载标签来将Angular应用程序嵌入到Confluence页面中。通过将此操作封装为用户宏,只需在页面中添加用户宏即可嵌入Angular应用程序。
准备静态文件
在Angular中通过ng build生成的文件中,将被index.html引用的文件复制到/confluence目录下。由于有多个文件,最好将它们整理到一个子目录中会更可靠。
<!doctype html>
<html lang="ja">
<head>
<meta name="decorator" content="none"/>
<base href=".">
<meta charset="utf-8">
<title>EmbedAngular</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!-- スタイルシート -->
<link rel="stylesheet" href="styles.09e2c710755c8867a460.css">
</head>
<body>
<app-root></app-root>
<!-- Javascript(古いブラウザを見限る設定の場合は3種類だけ) -->
<script src="runtime.69aad174de386c36a16c.js" defer></script>
<script src="polyfills.18e909cd5b286120e7aa.js" defer></script>
<script src="main.5a641e340bf9373c7a35.js" defer></script>
</body>
</html>
为了方便从用户宏中引用,最好将样式表和JavaScript文件的文件名设置为以下格式。
-
- style.css
-
- runtime.js
-
- polyfills.js
- main.js
添加一个加载Javascript的用户宏
在展示Angular的用户宏中,除了展示Angular应用程序的之外,还需添加一个延迟加载JavaScript脚本的代码。(可能会让人想知道为什么要这样做,但这是为了避免后面提到的一些不明确的问题所必需的解决办法)
# BaseURLに対して、/confluence/angular 以下にAngular関連のファイルを置いている場合
## @noparams
<!-- ここにAngularのアプリが表示される -->
<app-root></app-root>
<!-- 遅延ロード用のスクリプト -->
<script type="text/javascript">
( () => {
//-----------------------------------------------------------------
const head = document.getElementsByTagName( 'head' )[0];
//-----------------------------------------------------------------
const link = document.createElement( 'link' );
link.setAttribute( 'rel', 'stylesheet' );
link.setAttribute( 'href', '/confluence/angular/styles.css' );
head.appendChild( link );
//-----------------------------------------------------------------
const scripts = [
'/confluence/angular/runtime.js',
'/confluence/angular/polyfills.js',
'/confluence/angular/main.js',
];
scripts.forEach( path => {
const elem = document.createElement( 'script' );
elem.setAttribute( 'type', 'text/javascript' );
elem.setAttribute( 'src', path );
head.appendChild( elem );
} );
//-----------------------------------------------------------------
} )();
</script>
如果发生MIME类型错误的情况
如果在控制台上出现与以下MIME类型相关的错误,可能是Javascript或CSS路径错误的原因。如果静态文件路径错误,Confluence会显示主页或其他内容,以至于返回的不是.js而是html,导致出现如下错误。
MIME タイプ (“text/html”) が許可されていないため、“...” からのモジュールの読み込みがブロックされました。
MIME タイプ (“text/html”) の不一致により “...” からのリソースがブロックされました (X-Content-Type-Options: nosniff)。
绊倒的地方
在Confluence页面中尝试将Angular显示出来,按照Angular的index.html创建了以下类似的用户宏,但结果并不如预期。打开显示页面后,发现Angular应用没有显示出来,而且用户宏后面的元素也不再被渲染。还发现在加载Javascript的约20秒时间内,Confluence上的用户界面无法正常操作。
## @noparams
<app-root></app-root>
<script src="/confluence/angular/runtime.js" defer></script>
<script src="/confluence/angular/polyfills.js" defer></script>
<script src="/confluence/angular/main.js" defer></script>
应用
如果将用户宏的脚本和样式表路径参数化,还可以通过一个用户宏适用于多个应用程序。当使用时需要注意。
总结起来
我介绍了如何使用Confluence的静态文件提供功能,在Confluence上显示使用Angular创建的应用程序的方法。
如果简单地将Confluence作为HTTP服务器,并使用Angular创建应用程序,并且只需要提供index.html文件的微小更改,然后将通过ng build生成的文件复制到/confluence目录下即可。
如果要在Confluence页面内嵌Angular应用程序并提供服务,需要将使用ng build生成的Javascript和CSS文件复制到/confluence目录下,并通过用户宏进行延迟加载(否则会导致显示不完整或影响加载过程中的用户输入)。