fix(app):redirect after 404

This commit is contained in:
Alex 2020-04-21 19:48:00 +03:00
parent 74c617dc80
commit a769ca67f5
10 changed files with 278 additions and 1 deletions

7
docs/versions.json Normal file
View file

@ -0,0 +1,7 @@
[
{
"checkoutTarget": "gh-pages-deploy-fix",
"path": "/ngx-admin/",
"isCurrent": true
}
]

View file

@ -28,7 +28,7 @@
"docs": "compodoc -p src/tsconfig.app.json -d docs",
"docs:build": "npm run build -- docs --prod --aot --base-href /ngx-admin/",
"docs:serve": "npm start -- docs --port 4100",
"docs:gh-pages": "npm run docs:build && npm run ngh -- --dir ./docs/dist",
"docs:gh-pages": "ts-node -P ./scripts/docs/tsconfig.json ./scripts/docs/build-docs.ts",
"prepush": "npm run lint:ci",
"release:changelog": "npm run conventional-changelog -- -p angular -i CHANGELOG.md -s",
"postinstall": "ngcc --properties es2015 es5 browser module main --first-only --create-ivy-entry-points"

123
scripts/docs/build-docs.ts Normal file
View file

@ -0,0 +1,123 @@
import { join } from 'path';
import { copy, mkdirp, remove, outputFile, writeJson, readJson } from 'fs-extra';
import { generateGithubSpaScript } from './ghspa-template';
import { runCommand } from './run-command';
import { log } from './log';
import { REPO_URL, OUT_DIR, REPO_OWNER, REPO_NAME } from './config';
const WORK_DIR = join(process.cwd(), '../_DOCS_BUILD_WORK_DIR_');
const MASTER_BRANCH_DIR = join(WORK_DIR, 'MASTER');
const DOCS_VERSIONS_PATH = join(MASTER_BRANCH_DIR, 'docs/versions.json');
export interface Version {
checkoutTarget: string;
name: string;
path: string;
isCurrent?: boolean;
}
(async function () {
log(`Cleaning work dir "${WORK_DIR}"`);
await remove(WORK_DIR);
log(`Cleaning output dir "${OUT_DIR}"`);
await remove(OUT_DIR);
log(`Creating work dir "${WORK_DIR}"`);
await mkdirp(WORK_DIR);
log(`Cloning ${REPO_URL} into ${MASTER_BRANCH_DIR}`);
await runCommand(`git clone ${REPO_URL} ${MASTER_BRANCH_DIR}`, { cwd: WORK_DIR });
log('Reading versions configuration');
const config: Version[] = await import(DOCS_VERSIONS_PATH);
ensureSingleCurrentVersion(config);
log(`Versions configuration:`);
const jsonConfig = JSON.stringify(config, null, ' ');
log(jsonConfig);
log(`Building docs`);
await buildDocs(config);
log(`Adding versions.json to ${OUT_DIR}`);
await outputFile(join(OUT_DIR, 'versions.json'), jsonConfig);
log(`Deploying to ghpages`);
await deploy(OUT_DIR);
log(`Cleaning up working directory (${WORK_DIR})`);
await remove(WORK_DIR);
}());
function ensureSingleCurrentVersion(versions: Version[]) {
const currentVersion = versions.filter(v => v.isCurrent);
if (currentVersion.length !== 1) {
throw new Error(`Versions config error: Only one current version allowed.`)
}
}
async function buildDocs(versions: Version[]) {
const ghspaScript = generateGithubSpaScript(versions);
return Promise.all(versions.map((version: Version) => {
const versionDistDir = version.isCurrent
? OUT_DIR
: join(OUT_DIR, version.name);
return prepareVersion(version, versionDistDir, ghspaScript);
}));
}
async function prepareVersion(version: Version, distDir: string, ghspaScript: string) {
const projectDir = join(WORK_DIR, `${version.name}`);
await copyToBuildDir(MASTER_BRANCH_DIR, projectDir);
await checkoutVersion(version.checkoutTarget, projectDir);
await runCommand('npm install', { cwd: projectDir });
await addVersionNameToPackageJson(version.name, join(projectDir, 'package.json'));
await buildDocsApp(projectDir, version.path);
await copy(join(projectDir, 'docs/dist'), distDir);
await outputFile(join(distDir, 'assets/ghspa.js'), ghspaScript);
await remove(projectDir);
}
async function copyToBuildDir(from: string, to: string) {
try {
await mkdirp(to);
await copy(from, to);
} catch (e) {
throw new Error(`Error copying from ${from} to ${to}: ${e.message}`);
}
}
async function checkoutVersion(checkoutTarget: string, repoDirectory: string) {
try {
await runCommand(`git checkout ${checkoutTarget}`, { cwd: repoDirectory, showLog: false });
} catch (e) {
throw new Error(`Error checking out ${checkoutTarget}: ${e.message}`);
}
}
async function addVersionNameToPackageJson(versionName: string, packageJsonPath: string) {
const packageJsonObject = await readJson(packageJsonPath);
packageJsonObject.versionName = versionName;
await writeJson(packageJsonPath, packageJsonObject);
}
async function buildDocsApp(projectDir: string, baseHref: string) {
if (!baseHref.endsWith('/')) {
baseHref = baseHref + '/';
}
await runCommand('npm run docs:prepare', { cwd: projectDir });
await runCommand(`npm run build -- docs --prod --base-href '${baseHref}'`, { cwd: projectDir });
await runCommand('npm run docs:dirs', { cwd: projectDir });
}
async function deploy(distDir: string) {
await runCommand(
`npx angular-cli-ghpages --dir . --repo=https://GH_TOKEN@github.com/${REPO_OWNER}/${REPO_NAME}.git`,
{ cwd: distDir, showLog: true },
);
}

4
scripts/docs/config.ts Normal file
View file

@ -0,0 +1,4 @@
export const REPO_URL = 'https://github.com/akveo/ngx-admin.git';
export const REPO_OWNER = 'akveo';
export const REPO_NAME = 'ngx-admin';
export const OUT_DIR = 'docs/dist'; // Relative to the directory you run command

View file

@ -0,0 +1,78 @@
import { Version } from './build-docs';
function removeTrailingSlash(path: string): string {
if (path.endsWith('/')) {
return path.slice(0, -1);
}
return path;
}
export function generateGithubSpaScript(versionsToRedirect: Version[]): string {
const paths: string[] = versionsToRedirect.map(v => v.path).map(removeTrailingSlash);
return `
/**
*
* ____ _ ___ _ _ _ _ ___ ___ ____ ____ ____ ____ ____ ___ ____
* | __ | | |__| | | |__] |__] |__| | __ |___ [__ [__ |__] |__|
* |__] | | | | |__| |__] | | | |__] |___ ___] ___] | | |
*
* Easy way to enable Single Page Applications for GitHub Pages
*
* This project was released under MIT license.
*
* @link https://github.com/rafrex/spa-github-pages
* @author Rafael Pedicini <code@rafrex.com>
* @link http://websemantics.ca
* @author Adnan M.Sagar, PhD. <adnan@websemantics.ca>
*
* @param {Object} l, the document current location
* @param {Boolean} projectPages, true by default, https://help.github.com/articles/user-organization-and-project-pages
*
*/
;(function(l) {
var redirectPath;
${JSON.stringify(paths)}.forEach(function (path) {
if (l.pathname.indexOf(path) === 0) {
redirectPath = path;
}
});
if (!redirectPath) {
return;
}
/* redirect all 404 traffic to index.html */
function redirect() {
l.replace(l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') + redirectPath + '/?' +
(l.pathname ? 'p=' + l.pathname.replace(/&/g, '~and~').replace(redirectPath, '') : '') +
(l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +
(l.hash))
}
/* resolve 404 redirects into internal routes */
function resolve() {
if (l.search) {
var q = {};
l.search.slice(1).split('&').forEach(function(v) {
var a = v.split('=');
q[a[0]] = a.slice(1).join('=').replace(/~and~/g, '&')
});
if (q.p !== undefined) {
window.history.replaceState(null, null,
redirectPath + (q.p || '') +
(q.q ? ('?' + q.q) : '') +
l.hash
)
}
}
}
/* if current document is 404 page page, redirect to index.html otherwise resolve */
document.title === '404' ? redirect() : resolve()
}(window.location));
`;
}

3
scripts/docs/log.ts Normal file
View file

@ -0,0 +1,3 @@
export function log(message: string) {
console.log(message);
}

View file

@ -0,0 +1,37 @@
import { exec } from 'child_process';
import { promisify } from 'util';
export interface RunCommandOptions {
cwd?: string;
showLog?: boolean;
}
const DEFAULT_OPTIONS: RunCommandOptions = { cwd: process.cwd(), showLog: false };
export async function runCommand(command: string, options?: RunCommandOptions) {
let { cwd, showLog } = Object.assign({}, DEFAULT_OPTIONS, options);
try {
console.log(`Running "${command}" in "${cwd}"`);
const { stdout, stderr } = await promisify(exec)(command, { cwd });
if (showLog && stdout) {
console.log(stdout);
}
if (stderr) {
console.log(`stderr from "${command}" in "${cwd}"`);
console.warn(stderr);
}
} catch ({ message, stdout, stderr }) {
let errorMessage = `Error running "${command}" in "${cwd}": ${message}.`;
if (stdout) {
errorMessage += `\nstdout: ${stdout}`;
console.error(stdout);
}
if (stderr) {
errorMessage += `\nstderr: ${stderr}`;
}
throw new Error(errorMessage);
}
}

View file

@ -0,0 +1,12 @@
{
"compilerOptions": {
"rootDir": ".",
"module": "commonjs",
"lib": ["es2018"],
"target": "es2018",
"resolveJsonModule": true
},
"include": [
"build-docs.ts"
]
}

5
scripts/docs/tslint.json Normal file
View file

@ -0,0 +1,5 @@
{
"rules": {
"no-console": false
}
}

8
scripts/publish.sh Normal file
View file

@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Iterates over all modules bundled in the src/.lib and publish them
for dir in ./src/.lib/*/
do
dir=${dir%*/}
npm publish --access=public src/.lib/${dir##*/}
done