[\s\S]*?<\/code>/],
- minifyCSS: true,
- minifyJS: true,
- removeComments: true,
- removeScriptTypeAttributes: true,
- removeStyleLinkTypeAttributes: true,
-};
-
-function composePage(url) {
- console.log(`pre-rendering ${url}...`);
- const { title, contents } = JSON.parse(fs.readFileSync(`./dist/generated/docs/${url}.json`, 'utf-8'));
-
- if (!contents) {
- return;
- }
- const ssrContent = contents.replace(/href="(?!http)(.{2,}?)"/gi, 'href="/$1"');
- const pageContent = pageTemplate
- .replace('Angular Docs ', `${title} - Angular 官方文档 `)
- .replace('',
- `${ssrContent} `);
- mkdirp.sync(path.dirname(`./dist/${url}`));
- fs.writeFileSync(`./dist/${url}.html`, minify(pageContent, minifyOptions), 'utf-8');
-}
-
-function buildGuidePages(): void {
- const navigation = fs.readFileSync('./content/navigation.json', 'utf-8');
- (navigation.match(/"url": "(.*?)"/g) || [])
- .map((entry) => entry.replace(/^"url": "(.*?)".*$/, '$1'))
- .filter(url => url.slice(0, 4) !== 'http')
- .forEach(url => composePage(url));
-}
-
-function buildApiPages(): void {
- const apiList = klawSync('./dist/generated/docs/api', { nodir: true })
- .map(file => file.path.replace(/^.*generated\/docs(\/.*).json$/, '$1'));
- apiList.forEach(url => composePage(url));
-
- const links = apiList.map(url => `${url}`).join('\n');
- const apiListContent = fs.readFileSync('./dist/api.html', 'utf-8')
- .replace(rootElementPattern, `API List
${links} `);
-
- fs.writeFileSync(`./dist/api.html`, minify(apiListContent, minifyOptions), 'utf-8');
-}
-
-function buildIndexPage(): void {
- const indexTemplate = fs.readFileSync('./dist/index.html', 'utf-8');
- const aioShellIndex = fs.readFileSync(__dirname + '/../assets/aio-shell-index.html');
- const content = indexTemplate.replace(rootElementPattern, `${aioShellIndex}`);
- fs.writeFileSync(`./dist/index.html`, minify(content, minifyOptions), 'utf-8');
-}
-
-buildGuidePages();
-buildApiPages();
-buildIndexPage();
diff --git a/aio/tools/translator/ssr/ssr-server.js b/aio/tools/translator/ssr/ssr-server.js
new file mode 100644
index 0000000000..81585ab955
--- /dev/null
+++ b/aio/tools/translator/ssr/ssr-server.js
@@ -0,0 +1,3 @@
+const prerender = require('prerender');
+const server = prerender();
+server.start();
diff --git a/aio/tools/translator/ssr/ssr.ts b/aio/tools/translator/ssr/ssr.ts
new file mode 100644
index 0000000000..f44b14c684
--- /dev/null
+++ b/aio/tools/translator/ssr/ssr.ts
@@ -0,0 +1,55 @@
+import * as fs from 'fs';
+import * as klawSync from 'klaw-sync';
+import { concat, defer, Observable } from 'rxjs';
+import * as fetch from 'node-fetch';
+import { fromPromise } from 'rxjs/internal-compatibility';
+import { map } from 'rxjs/operators';
+import * as path from 'path';
+import { minify } from 'html-minifier';
+import mkdirp = require('mkdirp');
+
+const minifyOptions = {
+ collapseWhitespace: true,
+ ignoreCustomFragments: [/[\s\S]*?<\/code>/],
+ minifyCSS: true,
+ minifyJS: true,
+ removeComments: true,
+ removeScriptTypeAttributes: true,
+ removeStyleLinkTypeAttributes: true,
+};
+
+function renderPage(url: string): Observable {
+ return defer(() => fromPromise(fetch(`http://localhost:3000/render?url=http://localhost:4200/${url}`).then(resp => resp.text()))).pipe(
+ map(content => {
+ const filename = path.join('dist', `${url}.html`);
+ mkdirp.sync(path.dirname(filename));
+ fs.writeFileSync(filename, minify(content, minifyOptions), 'utf-8');
+ console.log(`rendered ${url}...`);
+ }),
+ );
+}
+
+function getGuideUrls(): string[] {
+ const navigation = fs.readFileSync('./content/navigation.json', 'utf-8');
+ return (navigation.match(/"url": "(.*?)"/g) || [])
+ .map((entry) => entry.replace(/^"url": "(.*?)".*$/, '$1'))
+ .filter(url => url.slice(0, 4) !== 'http');
+}
+
+function getApiUrls(): string[] {
+ return klawSync('./dist/generated/docs/api', { nodir: true })
+ .map(file => file.path.replace(/^.*generated\/docs\/(.*).json$/, '$1'));
+}
+
+const urls = [...getGuideUrls(), ...getApiUrls(), 'index.html'];
+const tasks = urls.map(url => renderPage(url));
+concat(...tasks).subscribe((url) => {
+}, () => {
+}, () => {
+ process.exit(0);
+});
+
+// 不自动退出
+setInterval(function () {
+}, 24 * 60 * 60 * 1000);
+
diff --git a/aio/tools/translator/tsconfig.json b/aio/tools/translator/tsconfig.json
new file mode 100644
index 0000000000..f5b6194e92
--- /dev/null
+++ b/aio/tools/translator/tsconfig.json
@@ -0,0 +1,28 @@
+{
+ "compileOnSave": true,
+ "compilerOptions": {
+ "strict": true,
+ "noImplicitAny": false,
+ "outDir": "dist",
+ "baseUrl": "src",
+ "module": "commonjs",
+ "sourceMap": true,
+ "declaration": true,
+ "moduleResolution": "node",
+ "noUnusedLocals": true,
+ "target": "es5",
+ "typeRoots": [
+ "node_modules/@types"
+ ],
+ "types": [
+ "node"
+ ],
+ "lib": [
+ "es2017",
+ "dom"
+ ]
+ },
+ "exclude": [
+ "**/*.spec.ts"
+ ]
+}
diff --git a/aio/yarn.lock b/aio/yarn.lock
index 30e8f0ccf6..e1e128ec6a 100644
--- a/aio/yarn.lock
+++ b/aio/yarn.lock
@@ -1300,7 +1300,7 @@ body-parser@1.18.2, body-parser@^1.16.1:
raw-body "2.3.2"
type-is "~1.6.15"
-body-parser@1.18.3, body-parser@^1.18.3:
+body-parser@1.18.3, body-parser@^1.18.3, body-parser@~1.18.3:
version "1.18.3"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
dependencies:
@@ -1867,6 +1867,14 @@ chrome-launcher@^0.10.5:
mkdirp "0.5.1"
rimraf "^2.6.1"
+chrome-remote-interface@~0.25.7:
+ version "0.25.7"
+ resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.25.7.tgz#827e85fbef3cc561a9ef2404eb7eee355968c5bc"
+ integrity sha512-6zI6LbR2IiGmduFZededaerEr9hHXabxT/L+fRrdq65a0CfyLMzpq0BKuZiqN0Upqcacsb6q2POj7fmobwBsEA==
+ dependencies:
+ commander "2.11.x"
+ ws "3.3.x"
+
chrome-trace-event@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48"
@@ -2098,6 +2106,10 @@ comma-separated-tokens@^1.0.0, comma-separated-tokens@^1.0.1:
dependencies:
trim "0.0.1"
+commander@2.11.x, commander@^2.8.1, commander@~2.11.0:
+ version "2.11.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
+
commander@2.15.1, commander@^2.12.1, commander@^2.9.0:
version "2.15.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
@@ -2106,10 +2118,6 @@ commander@2.17.x, commander@~2.17.1:
version "2.17.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
-commander@^2.8.1, commander@~2.11.0:
- version "2.11.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
-
commander@~2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
@@ -2153,7 +2161,7 @@ compress-commons@^1.2.0:
normalize-path "^2.0.0"
readable-stream "^2.0.0"
-compressible@^2.0.12:
+compressible@^2.0.12, compressible@~2.0.14:
version "2.0.15"
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.15.tgz#857a9ab0a7e5a07d8d837ed43fe2defff64fe212"
dependencies:
@@ -2195,6 +2203,19 @@ compression@^1.7.0:
safe-buffer "5.1.1"
vary "~1.1.2"
+compression@~1.7.3:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db"
+ integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==
+ dependencies:
+ accepts "~1.3.5"
+ bytes "3.0.0"
+ compressible "~2.0.14"
+ debug "2.6.9"
+ on-headers "~1.0.1"
+ safe-buffer "5.1.2"
+ vary "~1.1.2"
+
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -3529,7 +3550,7 @@ express@^4.16.2:
utils-merge "1.0.1"
vary "~1.1.2"
-express@^4.16.3:
+express@^4.16.3, express@~4.16.3:
version "4.16.4"
resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
dependencies:
@@ -4648,7 +4669,7 @@ hawk@~6.0.2:
hoek "4.x.x"
sntp "2.x.x"
-he@1.1.1, he@1.1.x:
+he@1.1.1, he@1.1.x, he@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
@@ -6937,6 +6958,11 @@ node-fetch-npm@^2.0.2:
json-parse-better-errors "^1.0.0"
safe-buffer "^5.1.1"
+node-fetch@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5"
+ integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==
+
node-forge@0.7.1, node-forge@^0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300"
@@ -7874,6 +7900,18 @@ prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
+prerender@^5.4.5:
+ version "5.4.5"
+ resolved "https://registry.yarnpkg.com/prerender/-/prerender-5.4.5.tgz#1ba1a1136a27362840fb0c2f97d3acfec35ecf0f"
+ integrity sha512-oA/tZpCcWkpUj7KLtBJfb46OZN5cQLgqnSLtG6VsQgpPglv/deP0UCNR3ZKoNrrJaxcruGhfwhPL3c8gx1ncuw==
+ dependencies:
+ body-parser "~1.18.3"
+ chrome-remote-interface "~0.25.7"
+ compression "~1.7.3"
+ express "~4.16.3"
+ he "~1.1.1"
+ valid-url "~1.0.9"
+
preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
@@ -10669,7 +10707,7 @@ v8flags@^3.0.0:
dependencies:
homedir-polyfill "^1.0.1"
-valid-url@^1:
+valid-url@^1, valid-url@~1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200"
@@ -11163,6 +11201,15 @@ ws@3.3.2:
safe-buffer "~5.1.0"
ultron "~1.1.0"
+ws@3.3.x:
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
+ integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==
+ dependencies:
+ async-limiter "~1.0.0"
+ safe-buffer "~5.1.0"
+ ultron "~1.1.0"
+
ws@^1.0.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61"