fix: 改用基于 Prerender 库的 SSR 方式
This commit is contained in:
commit
3dec4da2be
|
@ -9,6 +9,7 @@ addons:
|
|||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
chrome: stable
|
||||
branches:
|
||||
except:
|
||||
- g3
|
||||
|
@ -21,5 +22,6 @@ cache:
|
|||
before_install:
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.10.1
|
||||
- export PATH="$HOME/.yarn/bin:$PATH"
|
||||
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
|
||||
script:
|
||||
- "./aio/deploy-cn.sh"
|
||||
|
|
|
@ -9,7 +9,16 @@ commitMessage=$(git log --oneline -n 1)
|
|||
cd `dirname $0`
|
||||
|
||||
yarn build
|
||||
ts-node ./tools/translator/bin/ssr.ts
|
||||
|
||||
yarn start &
|
||||
|
||||
node ./tools/translator/ssr/ssr-server.js &
|
||||
|
||||
sleep 3;
|
||||
|
||||
ts-node ./tools/translator/ssr/ssr.ts
|
||||
|
||||
killall -9 node
|
||||
|
||||
if [[ ! -d "./ng-docs.github.io" ]]
|
||||
then
|
||||
|
|
|
@ -68,7 +68,9 @@
|
|||
"post~~build": "yarn build-404-page",
|
||||
"~~build-ie-polyfills": "webpack-cli src/ie-polyfills.js -o src/generated/ie-polyfills.min.js --mode production",
|
||||
"~~http-server": "http-server",
|
||||
"~~minify-lunr": "uglifyjs node_modules/lunr/lunr.js -c -m -o src/generated/lunr.min.js --source-map"
|
||||
"~~minify-lunr": "uglifyjs node_modules/lunr/lunr.js -c -m -o src/generated/lunr.min.js --source-map",
|
||||
"ssr-server": "node ./tools/translator/ssr/ssr-server.js",
|
||||
"ssr": "ts-node ./tools/translator/ssr/ssr.ts"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.9.0 <11.0.0",
|
||||
|
@ -93,6 +95,8 @@
|
|||
"classlist.js": "^1.1.20150312",
|
||||
"core-js": "^2.4.1",
|
||||
"klaw-sync": "^6.0.0",
|
||||
"node-fetch": "^2.3.0",
|
||||
"prerender": "^5.4.5",
|
||||
"rxjs": "^6.3.0",
|
||||
"tslib": "^1.9.0",
|
||||
"web-animations-js": "^2.2.5",
|
||||
|
|
|
@ -132,7 +132,7 @@ export const svgIconProviders = [
|
|||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserModule.withServerTransition({appId: 'ng-docs'}),
|
||||
BrowserAnimationsModule,
|
||||
CustomElementsModule,
|
||||
HttpClientModule,
|
||||
|
|
|
@ -8,5 +8,7 @@ if (environment.production) {
|
|||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
});
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<aio-shell ng-version="6.0.0"
|
||||
class="mode-stable sidenav-open page-guide-template-syntax folder-guide view-SideNav aio-notification-hide ">
|
||||
<ul role="navigation"><!---->
|
||||
<li class="ng-star-inserted"><a class="nav-link" href="/features" title="特性">特性</a></li>
|
||||
<li class="ng-star-inserted"><a class="nav-link" href="/docs" title="文档">文档</a></li>
|
||||
<li class="ng-star-inserted"><a class="nav-link" href="/resources" title="资源">资源</a></li>
|
||||
<li class="ng-star-inserted"><a class="nav-link" href="/events" title="会议">会议</a></li>
|
||||
<li class="ng-star-inserted"><a class="nav-link" href="https://blog.angular.io/" title="博客">博客</a></li>
|
||||
<li class="ng-star-inserted"><a class="nav-link" href="/translations/cn/home" title="关于中文版">关于中文版</a></li>
|
||||
<li class="ng-star-inserted"><a class="nav-link" href="https://ng-china.org" title="****2018 ngChina @ 杭州!****">****2018 ngChina @ 杭州!****</a></li>
|
||||
</ul>
|
||||
</aio-shell>
|
File diff suppressed because one or more lines are too long
|
@ -1,68 +0,0 @@
|
|||
import * as fs from 'fs';
|
||||
import * as mkdirp from 'mkdirp';
|
||||
import * as path from 'path';
|
||||
import * as klawSync from 'klaw-sync';
|
||||
import { minify } from 'html-minifier';
|
||||
|
||||
const rootElementPattern = /<aio-shell\b[\s\S]*<\/aio-shell>/;
|
||||
|
||||
const indexTemplate = fs.readFileSync('./dist/index.html', 'utf-8');
|
||||
const aioShellTemplate = fs.readFileSync(__dirname + '/../assets/aio-shell-template.html');
|
||||
const pageTemplate = indexTemplate.replace(rootElementPattern, `${aioShellTemplate}`);
|
||||
|
||||
const minifyOptions = {
|
||||
collapseWhitespace: true,
|
||||
ignoreCustomFragments: [/<code>[\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('<title>Angular Docs</title>', `<title>${title} - Angular 官方文档</title>`)
|
||||
.replace('<section class="sidenav-content" role="content" id="docs"></section>',
|
||||
`<section class="sidenav-content" role="content" id="docs">${ssrContent}</section>`);
|
||||
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 => `<a href="${url}">${url}</a>`).join('\n');
|
||||
const apiListContent = fs.readFileSync('./dist/api.html', 'utf-8')
|
||||
.replace(rootElementPattern, `<aio-shell><h3>API List</h3>${links}</aio-shell>`);
|
||||
|
||||
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();
|
|
@ -0,0 +1,3 @@
|
|||
const prerender = require('prerender');
|
||||
const server = prerender();
|
||||
server.start();
|
|
@ -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: [/<code>[\s\S]*?<\/code>/],
|
||||
minifyCSS: true,
|
||||
minifyJS: true,
|
||||
removeComments: true,
|
||||
removeScriptTypeAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
};
|
||||
|
||||
function renderPage(url: string): Observable<void> {
|
||||
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);
|
||||
|
|
@ -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"
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue