将使用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を埋め込む(ユーザの書いたページの内容を操作するのに使える)

完成想象

image.png

提供静态文件需要

按照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文件。

    1. 为了解决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中即可。

image.png

不能省略index.html文件。如果省略,将显示Confluence的主页。

这种方法简单方便,但需要注意的是,可以在没有Confluence登录的情况下进行浏览。

我在我的电脑上尝试了一下,发现通过Confluence进行显示比起ng serve时非常慢。我不太明白为什么加载Javascript要花费接近20秒的时间。如果直接打开Javascript只需要一瞬间,为什么会有这么大的差距呢?有没有进行某种后台检查?

将Angular嵌入到Confluence页面中

可以通过在Confluence页面中放置元素,并添加必要的脚本和样式表加载标签来将Angular应用程序嵌入到Confluence页面中。通过将此操作封装为用户宏,只需在页面中添加用户宏即可嵌入Angular应用程序。

image.png

准备静态文件

在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>
image.png

应用

image.png
image.png

如果将用户宏的脚本和样式表路径参数化,还可以通过一个用户宏适用于多个应用程序。当使用时需要注意。

总结起来

我介绍了如何使用Confluence的静态文件提供功能,在Confluence上显示使用Angular创建的应用程序的方法。

如果简单地将Confluence作为HTTP服务器,并使用Angular创建应用程序,并且只需要提供index.html文件的微小更改,然后将通过ng build生成的文件复制到/confluence目录下即可。

如果要在Confluence页面内嵌Angular应用程序并提供服务,需要将使用ng build生成的Javascript和CSS文件复制到/confluence目录下,并通过用户宏进行延迟加载(否则会导致显示不完整或影响加载过程中的用户输入)。