Revert "fix: 换成基于 protractor 的 prerender 方式"
This reverts commit bd6bc39c
This commit is contained in:
parent
bd6bc39c05
commit
4d5ff78d12
@ -9,7 +9,6 @@ addons:
|
|||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- g++-4.8
|
- g++-4.8
|
||||||
chrome: stable
|
|
||||||
branches:
|
branches:
|
||||||
except:
|
except:
|
||||||
- g3
|
- g3
|
||||||
@ -22,6 +21,5 @@ cache:
|
|||||||
before_install:
|
before_install:
|
||||||
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.10.1
|
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.10.1
|
||||||
- export PATH="$HOME/.yarn/bin:$PATH"
|
- export PATH="$HOME/.yarn/bin:$PATH"
|
||||||
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
|
|
||||||
script:
|
script:
|
||||||
- "./aio/deploy-cn.sh"
|
- "./aio/deploy-cn.sh"
|
||||||
|
@ -9,14 +9,7 @@ commitMessage=$(git log --oneline -n 1)
|
|||||||
cd `dirname $0`
|
cd `dirname $0`
|
||||||
|
|
||||||
yarn build
|
yarn build
|
||||||
|
ts-node ./tools/translator/bin/ssr.ts
|
||||||
yarn start &
|
|
||||||
|
|
||||||
sleep 10
|
|
||||||
|
|
||||||
yarn update-webdriver
|
|
||||||
|
|
||||||
yarn prerender
|
|
||||||
|
|
||||||
if [[ ! -d "./ng-docs.github.io" ]]
|
if [[ ! -d "./ng-docs.github.io" ]]
|
||||||
then
|
then
|
||||||
|
@ -68,8 +68,7 @@
|
|||||||
"post~~build": "yarn build-404-page",
|
"post~~build": "yarn build-404-page",
|
||||||
"~~build-ie-polyfills": "webpack-cli src/ie-polyfills.js -o src/generated/ie-polyfills.min.js --mode production",
|
"~~build-ie-polyfills": "webpack-cli src/ie-polyfills.js -o src/generated/ie-polyfills.min.js --mode production",
|
||||||
"~~http-server": "http-server",
|
"~~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"
|
||||||
"prerender": "protractor tests/e2e/protractor.conf.js --disableChecks --specs tests/e2e/prerender.e2e-spec.ts \"--grep=^Prerender \""
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.9.0 <11.0.0",
|
"node": ">=10.9.0 <11.0.0",
|
||||||
|
@ -132,7 +132,7 @@ export const svgIconProviders = [
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule.withServerTransition({appId: 'ng-docs'}),
|
BrowserModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
CustomElementsModule,
|
CustomElementsModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
|
@ -8,7 +8,5 @@ if (environment.production) {
|
|||||||
enableProdMode();
|
enableProdMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
});
|
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
import { browser, promise } from 'protractor';
|
|
||||||
import { readFileSync, writeFileSync } from 'fs';
|
|
||||||
import { concat, defer, Observable } from 'rxjs';
|
|
||||||
import { map, switchMap, tap } from 'rxjs/operators';
|
|
||||||
import * as path from 'path';
|
|
||||||
import * as mkdirp from 'mkdirp';
|
|
||||||
import { minify } from 'html-minifier';
|
|
||||||
import * as globby from 'globby';
|
|
||||||
|
|
||||||
const minifyOptions = {
|
|
||||||
collapseWhitespace: true,
|
|
||||||
ignoreCustomFragments: [/<code>[\s\S]*?<\/code>/],
|
|
||||||
minifyCSS: true,
|
|
||||||
minifyJS: true,
|
|
||||||
removeComments: true,
|
|
||||||
removeScriptTypeAttributes: true,
|
|
||||||
removeStyleLinkTypeAttributes: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
function fromPromise<T>(input: promise.Promise<T>): Observable<T> {
|
|
||||||
return Observable.create(observer => {
|
|
||||||
input.then((value) => {
|
|
||||||
observer.next(value);
|
|
||||||
observer.complete();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function prerender(url: string): Observable<any> {
|
|
||||||
return defer(() => fromPromise(browser.get(url))).pipe(
|
|
||||||
tap(() => browser.executeScript('document.body.classList.add(\'no-animations\')')),
|
|
||||||
tap(() => browser.waitForAngular()),
|
|
||||||
switchMap(() => fromPromise(browser.executeScript('return document.documentElement.outerHTML'))),
|
|
||||||
map(content => minify(content, minifyOptions)),
|
|
||||||
map((content) => `<!DOCTYPE html>${content}`),
|
|
||||||
tap((html) => {
|
|
||||||
const filename = path.join('dist', `${url}.html`);
|
|
||||||
mkdirp.sync(path.dirname(filename));
|
|
||||||
writeFileSync(filename, html, 'utf-8');
|
|
||||||
}),
|
|
||||||
tap(() => console.log('Rendered ', url)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGuideUrls(): string[] {
|
|
||||||
const navigation = 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 globby.sync('./src/generated/docs/api/**/*.json')
|
|
||||||
.map(file => file.replace(/^.*generated\/docs\/(.*).json$/, '$1'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function renderUrlsByTemplate(urls: string[], templateUrl: string): void {
|
|
||||||
const template = readFileSync(path.join('dist', `${templateUrl}.html`), 'utf-8');
|
|
||||||
urls.filter(url => url !== templateUrl).forEach((url) => {
|
|
||||||
console.log('Render by template: ', url);
|
|
||||||
const article = JSON.parse(readFileSync(`./src/generated/docs/${url}.json`, 'utf-8'));
|
|
||||||
const content = template
|
|
||||||
.replace(/<article>.*<\/article>/, article.contents)
|
|
||||||
.replace(/<title>.*<\/title>/, `${article.title} - Angular 官方文档`);
|
|
||||||
const filename = path.join('dist', `${url}.html`);
|
|
||||||
mkdirp.sync(path.dirname(filename));
|
|
||||||
writeFileSync(filename, content, 'utf-8');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Prerender', function () {
|
|
||||||
it('prerender', (done) => {
|
|
||||||
const apiUrls = getApiUrls();
|
|
||||||
const guideUrls = getGuideUrls().filter(url => url.match(/^(guide|tutorial|cli)/));
|
|
||||||
const otherUrls = getGuideUrls().filter(url => !url.match(/^(guide|tutorial|cli)/));
|
|
||||||
const urls = [guideUrls[0], apiUrls[0], otherUrls[0], 'index.html'];
|
|
||||||
const tasks = urls.map(url => prerender(url));
|
|
||||||
concat(...tasks).subscribe(undefined, undefined, () => {
|
|
||||||
console.log('Start render by template');
|
|
||||||
renderUrlsByTemplate(apiUrls, apiUrls[0]);
|
|
||||||
renderUrlsByTemplate(guideUrls, guideUrls[0]);
|
|
||||||
renderUrlsByTemplate(otherUrls, otherUrls[0]);
|
|
||||||
console.log('All rendered');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -3,9 +3,8 @@
|
|||||||
|
|
||||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
const MaxInt32 = Math.pow(2, 31) - 1;
|
|
||||||
exports.config = {
|
exports.config = {
|
||||||
allScriptsTimeout: MaxInt32,
|
allScriptsTimeout: 11000,
|
||||||
specs: [
|
specs: [
|
||||||
'./*.e2e-spec.ts'
|
'./*.e2e-spec.ts'
|
||||||
],
|
],
|
||||||
@ -13,6 +12,7 @@ exports.config = {
|
|||||||
browserName: 'chrome',
|
browserName: 'chrome',
|
||||||
// For Travis
|
// For Travis
|
||||||
chromeOptions: {
|
chromeOptions: {
|
||||||
|
binary: process.env.CHROME_BIN,
|
||||||
args: ['--no-sandbox']
|
args: ['--no-sandbox']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -21,7 +21,7 @@ exports.config = {
|
|||||||
framework: 'jasmine',
|
framework: 'jasmine',
|
||||||
jasmineNodeOpts: {
|
jasmineNodeOpts: {
|
||||||
showColors: true,
|
showColors: true,
|
||||||
defaultTimeoutInterval: MaxInt32,
|
defaultTimeoutInterval: 30000,
|
||||||
print: function() {}
|
print: function() {}
|
||||||
},
|
},
|
||||||
beforeLaunch: function() {
|
beforeLaunch: function() {
|
||||||
|
12
aio/tools/translator/assets/aio-shell-index.html
Normal file
12
aio/tools/translator/assets/aio-shell-index.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<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>
|
3
aio/tools/translator/assets/aio-shell-template.html
Normal file
3
aio/tools/translator/assets/aio-shell-template.html
Normal file
File diff suppressed because one or more lines are too long
68
aio/tools/translator/bin/ssr.ts
Normal file
68
aio/tools/translator/bin/ssr.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
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();
|
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"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"
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user