mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-14 03:54:46 +00:00
Compare commits
38 Commits
proxy-data
...
v0.17.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62b8a79e9f | ||
|
|
7f255563a4 | ||
|
|
32f4a50f25 | ||
|
|
b1a9be2dc3 | ||
|
|
c5456d3033 | ||
|
|
9b33dad589 | ||
|
|
4315a46ff2 | ||
|
|
0fb5827968 | ||
|
|
f9bf23dc43 | ||
|
|
611017fd28 | ||
|
|
72b265a35f | ||
|
|
e0d533f2ea | ||
|
|
dba83641e4 | ||
|
|
14e5c8e761 | ||
|
|
cbbf4a95db | ||
|
|
55b7ffd2ed | ||
|
|
9f4d4e70de | ||
|
|
deef1bbfcf | ||
|
|
17b0fc0d0c | ||
|
|
3c44c511e4 | ||
|
|
7cf1b9613a | ||
|
|
99e5a9601c | ||
|
|
4c9c1dccf5 | ||
|
|
2cddd5afa0 | ||
|
|
8c6a0c4773 | ||
|
|
af5063552d | ||
|
|
419d154794 | ||
|
|
abda059be5 | ||
|
|
444908cac5 | ||
|
|
c6da26e1a0 | ||
|
|
aad87857ce | ||
|
|
666c113297 | ||
|
|
84a58f34a0 | ||
|
|
75f5b5c721 | ||
|
|
a176a3b79b | ||
|
|
1627a5767a | ||
|
|
6ff3a9e9ab | ||
|
|
3ce2bd30f9 |
@@ -18,4 +18,4 @@ addons:
|
|||||||
install:
|
install:
|
||||||
- export DISPLAY=':99.0'
|
- export DISPLAY=':99.0'
|
||||||
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
|
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
|
||||||
- npm install
|
- npm ci || npm i
|
||||||
|
|||||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -1,5 +1,35 @@
|
|||||||
# sapper changelog
|
# sapper changelog
|
||||||
|
|
||||||
|
## 0.17.1
|
||||||
|
|
||||||
|
* Print which file is causing build errors/warnings ([#371](https://github.com/sveltejs/sapper/pull/371))
|
||||||
|
|
||||||
|
## 0.17.0
|
||||||
|
|
||||||
|
* Use `cheap-watch` instead of `chokidar` ([#364](https://github.com/sveltejs/sapper/issues/364))
|
||||||
|
|
||||||
|
## 0.16.1
|
||||||
|
|
||||||
|
* Fix file watching regression in previous version
|
||||||
|
|
||||||
|
## 0.16.0
|
||||||
|
|
||||||
|
* Slim down installed package ([#363](https://github.com/sveltejs/sapper/pull/363))
|
||||||
|
|
||||||
|
## 0.15.8
|
||||||
|
|
||||||
|
* Only set `preloading: true` on navigation, not prefetch ([#352](https://github.com/sveltejs/sapper/issues/352))
|
||||||
|
* Provide fallback for missing preload errors ([#361](https://github.com/sveltejs/sapper/pull/361))
|
||||||
|
|
||||||
|
## 0.15.7
|
||||||
|
|
||||||
|
* Strip leading slash from redirects ([#291](https://github.com/sveltejs/sapper/issues/291))
|
||||||
|
* Pass `(req, res)` to store getter ([#344](https://github.com/sveltejs/sapper/issues/344))
|
||||||
|
|
||||||
|
## 0.15.6
|
||||||
|
|
||||||
|
* Fix exporting with custom basepath ([#342](https://github.com/sveltejs/sapper/pull/342))
|
||||||
|
|
||||||
## 0.15.5
|
## 0.15.5
|
||||||
|
|
||||||
* Faster `export` with more explanatory output ([#335](https://github.com/sveltejs/sapper/pull/335))
|
* Faster `export` with more explanatory output ([#335](https://github.com/sveltejs/sapper/pull/335))
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ environment:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
- ps: Install-Product node $env:nodejs_version
|
- ps: Install-Product node $env:nodejs_version
|
||||||
- npm install
|
- npm ci
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- node --version && npm --version
|
- node --version && npm --version
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
--require source-map-support/register
|
--require source-map-support/register
|
||||||
|
--require ts-node/register
|
||||||
--recursive
|
--recursive
|
||||||
test/unit/*/*.js
|
test/unit/*/*.ts
|
||||||
test/common/test.js
|
test/common/test.js
|
||||||
3103
package-lock.json
generated
3103
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
55
package.json
55
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sapper",
|
"name": "sapper",
|
||||||
"version": "0.15.4",
|
"version": "0.17.1",
|
||||||
"description": "Military-grade apps, engineered by Svelte",
|
"description": "Military-grade apps, engineered by Svelte",
|
||||||
"main": "dist/middleware.ts.js",
|
"main": "dist/middleware.ts.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -19,50 +19,53 @@
|
|||||||
"test": "test"
|
"test": "test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-colors": "^2.0.1",
|
"html-minifier": "^3.5.16",
|
||||||
"cheerio": "^1.0.0-rc.2",
|
"source-map-support": "^0.5.6",
|
||||||
"chokidar": "^2.0.3",
|
"tslib": "^1.9.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/glob": "^5.0.34",
|
||||||
|
"@types/mkdirp": "^0.5.2",
|
||||||
|
"@types/mocha": "^5.2.5",
|
||||||
|
"@types/node": "^10.7.1",
|
||||||
|
"@types/rimraf": "^2.0.2",
|
||||||
|
"cheap-watch": "^0.3.0",
|
||||||
|
"compression": "^1.7.1",
|
||||||
"cookie": "^0.3.1",
|
"cookie": "^0.3.1",
|
||||||
"devalue": "^1.0.4",
|
"devalue": "^1.0.4",
|
||||||
"glob": "^7.1.2",
|
"eslint": "^4.13.1",
|
||||||
"html-minifier": "^3.5.16",
|
"eslint-plugin-import": "^2.12.0",
|
||||||
|
"express": "^4.16.3",
|
||||||
|
"kleur": "^2.0.1",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
|
"mocha": "^5.2.0",
|
||||||
|
"nightmare": "^3.0.0",
|
||||||
"node-fetch": "^2.1.1",
|
"node-fetch": "^2.1.1",
|
||||||
|
"npm-run-all": "^4.1.3",
|
||||||
|
"polka": "^0.4.0",
|
||||||
"port-authority": "^1.0.5",
|
"port-authority": "^1.0.5",
|
||||||
"pretty-bytes": "^5.0.0",
|
"pretty-bytes": "^5.0.0",
|
||||||
"pretty-ms": "^3.1.0",
|
"pretty-ms": "^3.1.0",
|
||||||
"require-relative": "^0.8.7",
|
"require-relative": "^0.8.7",
|
||||||
"rimraf": "^2.6.2",
|
"rimraf": "^2.6.2",
|
||||||
"sade": "^1.4.1",
|
|
||||||
"sander": "^0.6.0",
|
|
||||||
"source-map-support": "^0.5.6",
|
|
||||||
"tslib": "^1.9.1",
|
|
||||||
"url-parse": "^1.2.0",
|
|
||||||
"webpack-format-messages": "^2.0.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/glob": "^5.0.34",
|
|
||||||
"@types/mkdirp": "^0.5.2",
|
|
||||||
"@types/rimraf": "^2.0.2",
|
|
||||||
"compression": "^1.7.1",
|
|
||||||
"eslint": "^4.13.1",
|
|
||||||
"eslint-plugin-import": "^2.12.0",
|
|
||||||
"express": "^4.16.3",
|
|
||||||
"mocha": "^5.2.0",
|
|
||||||
"nightmare": "^3.0.0",
|
|
||||||
"npm-run-all": "^4.1.3",
|
|
||||||
"polka": "^0.4.0",
|
|
||||||
"rollup": "^0.59.2",
|
"rollup": "^0.59.2",
|
||||||
"rollup-plugin-commonjs": "^9.1.3",
|
"rollup-plugin-commonjs": "^9.1.3",
|
||||||
"rollup-plugin-json": "^3.0.0",
|
"rollup-plugin-json": "^3.0.0",
|
||||||
|
"rollup-plugin-node-resolve": "^3.3.0",
|
||||||
"rollup-plugin-string": "^2.0.2",
|
"rollup-plugin-string": "^2.0.2",
|
||||||
"rollup-plugin-typescript": "^0.8.1",
|
"rollup-plugin-typescript": "^0.8.1",
|
||||||
|
"sade": "^1.4.1",
|
||||||
|
"sander": "^0.6.0",
|
||||||
"serve-static": "^1.13.2",
|
"serve-static": "^1.13.2",
|
||||||
"svelte": "^2.6.3",
|
"svelte": "^2.6.3",
|
||||||
"svelte-loader": "^2.9.0",
|
"svelte-loader": "^2.9.0",
|
||||||
|
"tiny-glob": "^0.2.2",
|
||||||
|
"ts-node": "^7.0.1",
|
||||||
"typescript": "^2.8.3",
|
"typescript": "^2.8.3",
|
||||||
|
"url-parse": "^1.2.0",
|
||||||
"walk-sync": "^0.3.2",
|
"walk-sync": "^0.3.2",
|
||||||
"webpack": "^4.8.3"
|
"webpack": "^4.8.3",
|
||||||
|
"webpack-format-messages": "^2.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"cy:open": "cypress open",
|
"cy:open": "cypress open",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import typescript from 'rollup-plugin-typescript';
|
import typescript from 'rollup-plugin-typescript';
|
||||||
import string from 'rollup-plugin-string';
|
import string from 'rollup-plugin-string';
|
||||||
import json from 'rollup-plugin-json';
|
import json from 'rollup-plugin-json';
|
||||||
|
import resolve from 'rollup-plugin-node-resolve';
|
||||||
import commonjs from 'rollup-plugin-commonjs';
|
import commonjs from 'rollup-plugin-commonjs';
|
||||||
import pkg from './package.json';
|
import pkg from './package.json';
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ export default [
|
|||||||
include: '**/*.md'
|
include: '**/*.md'
|
||||||
}),
|
}),
|
||||||
json(),
|
json(),
|
||||||
|
resolve(),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
typescript({
|
typescript({
|
||||||
typescript: require('typescript')
|
typescript: require('typescript')
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as path from 'path';
|
|||||||
import mkdirp from 'mkdirp';
|
import mkdirp from 'mkdirp';
|
||||||
import rimraf from 'rimraf';
|
import rimraf from 'rimraf';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { minify_html } from './utils/minify_html';
|
import minify_html from './utils/minify_html';
|
||||||
import { create_compilers, create_main_manifests, create_routes, create_serviceworker_manifest } from '../core';
|
import { create_compilers, create_main_manifests, create_routes, create_serviceworker_manifest } from '../core';
|
||||||
import * as events from './interfaces';
|
import * as events from './interfaces';
|
||||||
|
|
||||||
|
|||||||
@@ -119,21 +119,30 @@ class Watcher extends EventEmitter {
|
|||||||
this.dev_server = new DevServer(dev_port);
|
this.dev_server = new DevServer(dev_port);
|
||||||
|
|
||||||
this.filewatchers.push(
|
this.filewatchers.push(
|
||||||
watch_files(locations.routes(), ['add', 'unlink'], () => {
|
watch_dir(
|
||||||
const routes = create_routes();
|
locations.routes(),
|
||||||
create_main_manifests({ routes, dev_port });
|
({ path: file, stats }) => {
|
||||||
|
if (stats.isDirectory()) {
|
||||||
try {
|
return path.basename(file)[0] !== '_';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
() => {
|
||||||
const routes = create_routes();
|
const routes = create_routes();
|
||||||
create_main_manifests({ routes, dev_port });
|
create_main_manifests({ routes, dev_port });
|
||||||
} catch (err) {
|
|
||||||
this.emit('error', <events.ErrorEvent>{
|
|
||||||
message: err.message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
watch_files(`${locations.app()}/template.html`, ['change'], () => {
|
try {
|
||||||
|
const routes = create_routes();
|
||||||
|
create_main_manifests({ routes, dev_port });
|
||||||
|
} catch (err) {
|
||||||
|
this.emit('error', <events.ErrorEvent>{
|
||||||
|
message: err.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|
||||||
|
fs.watch(`${locations.app()}/template.html`, () => {
|
||||||
this.dev_server.send({
|
this.dev_server.send({
|
||||||
action: 'reload'
|
action: 'reload'
|
||||||
});
|
});
|
||||||
@@ -453,20 +462,32 @@ class DevServer {
|
|||||||
|
|
||||||
function noop() {}
|
function noop() {}
|
||||||
|
|
||||||
function watch_files(pattern: string, events: string[], callback: () => void) {
|
function watch_dir(
|
||||||
const chokidar = require('chokidar');
|
dir: string,
|
||||||
|
filter: ({ path, stats }: { path: string, stats: fs.Stats }) => boolean,
|
||||||
|
callback: () => void
|
||||||
|
) {
|
||||||
|
let watch;
|
||||||
|
let closed = false;
|
||||||
|
|
||||||
const watcher = chokidar.watch(pattern, {
|
import('cheap-watch').then(CheapWatch => {
|
||||||
persistent: true,
|
if (closed) return;
|
||||||
ignoreInitial: true,
|
|
||||||
disableGlobbing: true
|
|
||||||
});
|
|
||||||
|
|
||||||
events.forEach(event => {
|
watch = new CheapWatch({ dir, filter, debounce: 50 });
|
||||||
watcher.on(event, callback);
|
|
||||||
|
watch.on('+', ({ isNew }) => {
|
||||||
|
if (isNew) callback();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch.on('-', callback);
|
||||||
|
|
||||||
|
watch.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
close: () => watcher.close()
|
close: () => {
|
||||||
|
if (watch) watch.close();
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import * as child_process from 'child_process';
|
import * as child_process from 'child_process';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as sander from 'sander';
|
import * as sander from 'sander';
|
||||||
import cheerio from 'cheerio';
|
|
||||||
import URL from 'url-parse';
|
import URL from 'url-parse';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import * as ports from 'port-authority';
|
import * as ports from 'port-authority';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { minify_html } from './utils/minify_html';
|
import clean_html from './utils/clean_html';
|
||||||
|
import minify_html from './utils/minify_html';
|
||||||
import Deferred from './utils/Deferred';
|
import Deferred from './utils/Deferred';
|
||||||
import * as events from './interfaces';
|
import * as events from './interfaces';
|
||||||
|
|
||||||
@@ -51,9 +51,10 @@ async function execute(emitter: EventEmitter, {
|
|||||||
const port = await ports.find(3000);
|
const port = await ports.find(3000);
|
||||||
|
|
||||||
const origin = `http://localhost:${port}`;
|
const origin = `http://localhost:${port}`;
|
||||||
|
const root = new URL(basepath || '', origin);
|
||||||
|
|
||||||
emitter.emit('info', {
|
emitter.emit('info', {
|
||||||
message: `Crawling ${origin}`
|
message: `Crawling ${root.href}`
|
||||||
});
|
});
|
||||||
|
|
||||||
const proc = child_process.fork(path.resolve(`${build}/server.js`), [], {
|
const proc = child_process.fork(path.resolve(`${build}/server.js`), [], {
|
||||||
@@ -71,8 +72,10 @@ async function execute(emitter: EventEmitter, {
|
|||||||
const deferreds = new Map();
|
const deferreds = new Map();
|
||||||
|
|
||||||
function get_deferred(pathname: string) {
|
function get_deferred(pathname: string) {
|
||||||
|
pathname = pathname.replace(root.pathname, '');
|
||||||
|
|
||||||
if (!deferreds.has(pathname)) {
|
if (!deferreds.has(pathname)) {
|
||||||
deferreds.set(pathname, new Deferred()) ;
|
deferreds.set(pathname, new Deferred());
|
||||||
}
|
}
|
||||||
|
|
||||||
return deferreds.get(pathname);
|
return deferreds.get(pathname);
|
||||||
@@ -107,7 +110,7 @@ async function execute(emitter: EventEmitter, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function handle(url: URL) {
|
async function handle(url: URL) {
|
||||||
const pathname = url.pathname || '/';
|
const pathname = (url.pathname.replace(root.pathname, '') || '/');
|
||||||
|
|
||||||
if (seen.has(pathname)) return;
|
if (seen.has(pathname)) return;
|
||||||
seen.add(pathname);
|
seen.add(pathname);
|
||||||
@@ -120,15 +123,26 @@ async function execute(emitter: EventEmitter, {
|
|||||||
if (range === 2) {
|
if (range === 2) {
|
||||||
if (r.headers.get('Content-Type') === 'text/html') {
|
if (r.headers.get('Content-Type') === 'text/html') {
|
||||||
const body = await r.text();
|
const body = await r.text();
|
||||||
const $ = cheerio.load(body);
|
|
||||||
const urls: URL[] = [];
|
const urls: URL[] = [];
|
||||||
|
|
||||||
const base = new URL($('base').attr('href') || '/', url.href);
|
const cleaned = clean_html(body);
|
||||||
|
|
||||||
$('a[href]').each((i: number, $a) => {
|
const base_match = /<base ([\s\S]+?)>/m.exec(cleaned);
|
||||||
const url = new URL($a.attribs.href, base.href);
|
const base_href = base_match && get_href(base_match[1]);
|
||||||
if (url.origin === origin) urls.push(url);
|
const base = new URL(base_href || '/', url.href);
|
||||||
});
|
|
||||||
|
let match;
|
||||||
|
let pattern = /<a ([\s\S]+?)>/gm;
|
||||||
|
|
||||||
|
while (match = pattern.exec(cleaned)) {
|
||||||
|
const attrs = match[1];
|
||||||
|
const href = get_href(attrs);
|
||||||
|
|
||||||
|
if (href) {
|
||||||
|
const url = new URL(href, base.href);
|
||||||
|
if (url.origin === origin) urls.push(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all(urls.map(handle));
|
await Promise.all(urls.map(handle));
|
||||||
}
|
}
|
||||||
@@ -138,6 +152,14 @@ async function execute(emitter: EventEmitter, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ports.wait(port)
|
return ports.wait(port)
|
||||||
.then(() => handle(new URL(`/${basepath}`, origin))) // TODO all static routes
|
.then(() => {
|
||||||
|
// TODO all static routes
|
||||||
|
return handle(root);
|
||||||
|
})
|
||||||
.then(() => proc.kill());
|
.then(() => proc.kill());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_href(attrs: string) {
|
||||||
|
const match = /href\s*=\s*(?:"(.+?)"|'(.+?)'|([^\s>]+))/.exec(attrs);
|
||||||
|
return match[1] || match[2] || match[3];
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import * as glob from 'glob';
|
|
||||||
import { locations } from '../config';
|
import { locations } from '../config';
|
||||||
import { create_routes } from '../core';
|
import { create_routes } from '../core';
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ export type InvalidEvent = {
|
|||||||
|
|
||||||
export type BuildEvent = {
|
export type BuildEvent = {
|
||||||
type: string;
|
type: string;
|
||||||
errors: Array<{ message: string, duplicate: boolean }>;
|
errors: Array<{ file: string, message: string, duplicate: boolean }>;
|
||||||
warnings: Array<{ message: string, duplicate: boolean }>;
|
warnings: Array<{ file: string, message: string, duplicate: boolean }>;
|
||||||
duration: number;
|
duration: number;
|
||||||
webpack_stats: any;
|
webpack_stats: any;
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/api/utils/clean_html.ts
Normal file
7
src/api/utils/clean_html.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function clean_html(html: string) {
|
||||||
|
return html
|
||||||
|
.replace(/<!\[CDATA\[[\s\S]*?\]\]>/gm, '')
|
||||||
|
.replace(/(<script[\s\S]*?>)[\s\S]*?<\/script>/gm, '$1</' + 'script>')
|
||||||
|
.replace(/(<style[\s\S]*?>)[\s\S]*?<\/style>/gm, '$1</' + 'style>')
|
||||||
|
.replace(/<!--[\s\S]*?-->/gm, '');
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { minify } from 'html-minifier';
|
import { minify } from 'html-minifier';
|
||||||
|
|
||||||
export function minify_html(html: string) {
|
export default function minify_html(html: string) {
|
||||||
return minify(html, {
|
return minify(html, {
|
||||||
collapseBooleanAttributes: true,
|
collapseBooleanAttributes: true,
|
||||||
collapseWhitespace: true,
|
collapseWhitespace: true,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import sade from 'sade';
|
import sade from 'sade';
|
||||||
import * as colors from 'ansi-colors';
|
import colors from 'kleur';
|
||||||
import prettyMs from 'pretty-ms';
|
import prettyMs from 'pretty-ms';
|
||||||
import * as pkg from '../package.json';
|
import * as pkg from '../package.json';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { build as _build } from '../api/build';
|
import { build as _build } from '../api/build';
|
||||||
import * as colors from 'ansi-colors';
|
import colors from 'kleur';
|
||||||
import { locations } from '../config';
|
import { locations } from '../config';
|
||||||
|
|
||||||
export function build() {
|
export function build() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as colors from 'ansi-colors';
|
import colors from 'kleur';
|
||||||
import * as child_process from 'child_process';
|
import * as child_process from 'child_process';
|
||||||
import prettyMs from 'pretty-ms';
|
import prettyMs from 'pretty-ms';
|
||||||
import { dev as _dev } from '../api/dev';
|
import { dev as _dev } from '../api/dev';
|
||||||
@@ -13,7 +13,7 @@ export function dev(opts: { port: number, open: boolean }) {
|
|||||||
|
|
||||||
watcher.on('ready', (event: events.ReadyEvent) => {
|
watcher.on('ready', (event: events.ReadyEvent) => {
|
||||||
if (first) {
|
if (first) {
|
||||||
console.log(`${colors.bold.cyan(`> Listening on http://localhost:${event.port}`)}`);
|
console.log(colors.bold.cyan(`> Listening on http://localhost:${event.port}`));
|
||||||
if (opts.open) child_process.exec(`open http://localhost:${event.port}`);
|
if (opts.open) child_process.exec(`open http://localhost:${event.port}`);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
@@ -35,20 +35,21 @@ export function dev(opts: { port: number, open: boolean }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
watcher.on('error', (event: events.ErrorEvent) => {
|
watcher.on('error', (event: events.ErrorEvent) => {
|
||||||
console.log(`${colors.red(`✗ ${event.type}`)}`);
|
console.log(colors.red(`✗ ${event.type}`));
|
||||||
console.log(`${colors.red(event.message)}`);
|
console.log(colors.red(event.message));
|
||||||
});
|
});
|
||||||
|
|
||||||
watcher.on('fatal', (event: events.FatalEvent) => {
|
watcher.on('fatal', (event: events.FatalEvent) => {
|
||||||
console.log(`${colors.bold.red(`> ${event.message}`)}`);
|
console.log(colors.bold.red(`> ${event.message}`));
|
||||||
if (event.log) console.log(event.log);
|
if (event.log) console.log(event.log);
|
||||||
});
|
});
|
||||||
|
|
||||||
watcher.on('build', (event: events.BuildEvent) => {
|
watcher.on('build', (event: events.BuildEvent) => {
|
||||||
if (event.errors.length) {
|
if (event.errors.length) {
|
||||||
console.log(`${colors.bold.red(`✗ ${event.type}`)}`);
|
console.log(colors.bold.red(`✗ ${event.type}`));
|
||||||
|
|
||||||
event.errors.filter(e => !e.duplicate).forEach(error => {
|
event.errors.filter(e => !e.duplicate).forEach(error => {
|
||||||
|
if (error.file) console.log(colors.bold(error.file));
|
||||||
console.log(error.message);
|
console.log(error.message);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -57,9 +58,10 @@ export function dev(opts: { port: number, open: boolean }) {
|
|||||||
console.log(`${hidden} duplicate ${hidden === 1 ? 'error' : 'errors'} hidden\n`);
|
console.log(`${hidden} duplicate ${hidden === 1 ? 'error' : 'errors'} hidden\n`);
|
||||||
}
|
}
|
||||||
} else if (event.warnings.length) {
|
} else if (event.warnings.length) {
|
||||||
console.log(`${colors.bold.yellow(`• ${event.type}`)}`);
|
console.log(colors.bold.yellow(`• ${event.type}`));
|
||||||
|
|
||||||
event.warnings.filter(e => !e.duplicate).forEach(warning => {
|
event.warnings.filter(e => !e.duplicate).forEach(warning => {
|
||||||
|
if (warning.file) console.log(colors.bold(warning.file));
|
||||||
console.log(warning.message);
|
console.log(warning.message);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -72,7 +74,7 @@ export function dev(opts: { port: number, open: boolean }) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(`${colors.bold.red(`> ${err.message}`)}`);
|
console.log(colors.bold.red(`> ${err.message}`));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { exporter as _exporter } from '../api/export';
|
import { exporter as _exporter } from '../api/export';
|
||||||
import * as colors from 'ansi-colors';
|
import colors from 'kleur';
|
||||||
import prettyBytes from 'pretty-bytes';
|
import prettyBytes from 'pretty-bytes';
|
||||||
import { locations } from '../config';
|
import { locations } from '../config';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as child_process from 'child_process';
|
import * as child_process from 'child_process';
|
||||||
import * as colors from 'ansi-colors';
|
import colors from 'kleur';
|
||||||
import * as ports from 'port-authority';
|
import * as ports from 'port-authority';
|
||||||
|
|
||||||
export async function start(dir: string, opts: { port: number, open: boolean }) {
|
export async function start(dir: string, opts: { port: number, open: boolean }) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as colors from 'ansi-colors';
|
import colors from 'kleur';
|
||||||
|
|
||||||
export default async function upgrade() {
|
export default async function upgrade() {
|
||||||
const upgraded = [
|
const upgraded = [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as glob from 'glob';
|
import glob from 'tiny-glob/sync.js';
|
||||||
import { posixify, write_if_changed } from './utils';
|
import { posixify, write_if_changed } from './utils';
|
||||||
import { dev, locations } from '../config';
|
import { dev, locations } from '../config';
|
||||||
import { Page, PageComponent, ServerRoute } from '../interfaces';
|
import { Page, PageComponent, ServerRoute } from '../interfaces';
|
||||||
@@ -9,24 +9,27 @@ export function create_main_manifests({ routes, dev_port }: {
|
|||||||
routes: { components: PageComponent[], pages: Page[], server_routes: ServerRoute[] };
|
routes: { components: PageComponent[], pages: Page[], server_routes: ServerRoute[] };
|
||||||
dev_port?: number;
|
dev_port?: number;
|
||||||
}) {
|
}) {
|
||||||
const path_to_routes = path.relative(`${locations.app()}/manifest`, locations.routes());
|
const manifest_dir = path.join(locations.app(), 'manifest');
|
||||||
|
if (!fs.existsSync(manifest_dir)) fs.mkdirSync(manifest_dir);
|
||||||
|
|
||||||
|
const path_to_routes = path.relative(manifest_dir, locations.routes());
|
||||||
|
|
||||||
const client_manifest = generate_client(routes, path_to_routes, dev_port);
|
const client_manifest = generate_client(routes, path_to_routes, dev_port);
|
||||||
const server_manifest = generate_server(routes, path_to_routes);
|
const server_manifest = generate_server(routes, path_to_routes);
|
||||||
|
|
||||||
write_if_changed(
|
write_if_changed(
|
||||||
`${locations.app()}/manifest/default-layout.html`,
|
`${manifest_dir}/default-layout.html`,
|
||||||
`<svelte:component this={child.component} {...child.props}/>`
|
`<svelte:component this={child.component} {...child.props}/>`
|
||||||
);
|
);
|
||||||
write_if_changed(`${locations.app()}/manifest/client.js`, client_manifest);
|
write_if_changed(`${manifest_dir}/client.js`, client_manifest);
|
||||||
write_if_changed(`${locations.app()}/manifest/server.js`, server_manifest);
|
write_if_changed(`${manifest_dir}/server.js`, server_manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function create_serviceworker_manifest({ routes, client_files }: {
|
export function create_serviceworker_manifest({ routes, client_files }: {
|
||||||
routes: { components: PageComponent[], pages: Page[], server_routes: ServerRoute[] };
|
routes: { components: PageComponent[], pages: Page[], server_routes: ServerRoute[] };
|
||||||
client_files: string[];
|
client_files: string[];
|
||||||
}) {
|
}) {
|
||||||
const assets = glob.sync('**', { cwd: 'assets', nodir: true });
|
const assets = glob('**', { cwd: 'assets', filesOnly: true });
|
||||||
|
|
||||||
let code = `
|
let code = `
|
||||||
// This file is generated by Sapper — do not edit it!
|
// This file is generated by Sapper — do not edit it!
|
||||||
@@ -42,11 +45,6 @@ export function create_serviceworker_manifest({ routes, client_files }: {
|
|||||||
write_if_changed(`${locations.app()}/manifest/service-worker.js`, code);
|
write_if_changed(`${locations.app()}/manifest/service-worker.js`, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
function right_pad(str: string, len: number) {
|
|
||||||
while (str.length < len) str += ' ';
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generate_client(
|
function generate_client(
|
||||||
routes: { root: PageComponent, components: PageComponent[], pages: Page[], server_routes: ServerRoute[] },
|
routes: { root: PageComponent, components: PageComponent[], pages: Page[], server_routes: ServerRoute[] },
|
||||||
path_to_routes: string,
|
path_to_routes: string,
|
||||||
|
|||||||
@@ -4,11 +4,6 @@ import { locations } from '../config';
|
|||||||
import { Page, PageComponent, ServerRoute } from '../interfaces';
|
import { Page, PageComponent, ServerRoute } from '../interfaces';
|
||||||
import { posixify } from './utils';
|
import { posixify } from './utils';
|
||||||
|
|
||||||
const default_layout_file = posixify(path.resolve(
|
|
||||||
__dirname,
|
|
||||||
'../components/default-layout.html'
|
|
||||||
));
|
|
||||||
|
|
||||||
export default function create_routes(cwd = locations.routes()) {
|
export default function create_routes(cwd = locations.routes()) {
|
||||||
const components: PageComponent[] = [];
|
const components: PageComponent[] = [];
|
||||||
const pages: Page[] = [];
|
const pages: Page[] = [];
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import * as sander from 'sander';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
const previous_contents = new Map();
|
const previous_contents = new Map();
|
||||||
|
|
||||||
export function write_if_changed(file: string, code: string) {
|
export function write_if_changed(file: string, code: string) {
|
||||||
if (code !== previous_contents.get(file)) {
|
if (code !== previous_contents.get(file)) {
|
||||||
previous_contents.set(file, code);
|
previous_contents.set(file, code);
|
||||||
sander.writeFileSync(file, code);
|
fs.writeFileSync(file, code);
|
||||||
fudge_mtime(file);
|
fudge_mtime(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,8 +16,8 @@ export function posixify(file: string) {
|
|||||||
|
|
||||||
export function fudge_mtime(file: string) {
|
export function fudge_mtime(file: string) {
|
||||||
// need to fudge the mtime so that webpack doesn't go doolally
|
// need to fudge the mtime so that webpack doesn't go doolally
|
||||||
const { atime, mtime } = sander.statSync(file);
|
const { atime, mtime } = fs.statSync(file);
|
||||||
sander.utimesSync(
|
fs.utimesSync(
|
||||||
file,
|
file,
|
||||||
new Date(atime.getTime() - 999999),
|
new Date(atime.getTime() - 999999),
|
||||||
new Date(mtime.getTime() - 999999)
|
new Date(mtime.getTime() - 999999)
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ function toIgnore(uri: string, val: any) {
|
|||||||
|
|
||||||
export default function middleware(opts: {
|
export default function middleware(opts: {
|
||||||
manifest: Manifest,
|
manifest: Manifest,
|
||||||
store: (req: Req) => Store,
|
store: (req: Req, res: ServerResponse) => Store,
|
||||||
ignore?: any,
|
ignore?: any,
|
||||||
routes?: any // legacy
|
routes?: any // legacy
|
||||||
}) {
|
}) {
|
||||||
@@ -276,7 +276,10 @@ function get_server_route_handler(routes: ServerRoute[]) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store) {
|
function get_page_handler(
|
||||||
|
manifest: Manifest,
|
||||||
|
store_getter: (req: Req, res: ServerResponse) => Store
|
||||||
|
) {
|
||||||
const output = locations.dest();
|
const output = locations.dest();
|
||||||
|
|
||||||
const get_chunks = dev()
|
const get_chunks = dev()
|
||||||
@@ -296,13 +299,10 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
parts: [
|
parts: [
|
||||||
{ name: null, component: error_route }
|
{ name: null, component: error_route }
|
||||||
]
|
]
|
||||||
}, req, res, statusCode, error);
|
}, req, res, statusCode, error || new Error('Unknown error in preload function'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_page(page: Page, req: Req, res: ServerResponse, status = 200, error: Error | string = null) {
|
function handle_page(page: Page, req: Req, res: ServerResponse, status = 200, error: Error | string = null) {
|
||||||
const get_params = page.parts[page.parts.length - 1].params || (() => ({}));
|
|
||||||
const match = error ? null : page.pattern.exec(req.path);
|
|
||||||
|
|
||||||
const chunks: Record<string, string | string[]> = get_chunks();
|
const chunks: Record<string, string | string[]> = get_chunks();
|
||||||
|
|
||||||
res.setHeader('Content-Type', 'text/html');
|
res.setHeader('Content-Type', 'text/html');
|
||||||
@@ -326,7 +326,7 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
|
|
||||||
res.setHeader('Link', link);
|
res.setHeader('Link', link);
|
||||||
|
|
||||||
const store = store_getter ? store_getter(req) : null;
|
const store = store_getter ? store_getter(req, res) : null;
|
||||||
|
|
||||||
let redirect: { statusCode: number, location: string };
|
let redirect: { statusCode: number, location: string };
|
||||||
let preload_error: { statusCode: number, message: Error | string };
|
let preload_error: { statusCode: number, message: Error | string };
|
||||||
@@ -336,6 +336,7 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
if (redirect && (redirect.statusCode !== statusCode || redirect.location !== location)) {
|
if (redirect && (redirect.statusCode !== statusCode || redirect.location !== location)) {
|
||||||
throw new Error(`Conflicting redirects`);
|
throw new Error(`Conflicting redirects`);
|
||||||
}
|
}
|
||||||
|
location = location.replace(/^\//g, ''); // leading slash (only)
|
||||||
redirect = { statusCode, location };
|
redirect = { statusCode, location };
|
||||||
},
|
},
|
||||||
error: (statusCode: number, message: Error | string) => {
|
error: (statusCode: number, message: Error | string) => {
|
||||||
@@ -387,6 +388,8 @@ function get_page_handler(manifest: Manifest, store_getter: (req: Req) => Store)
|
|||||||
})
|
})
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
|
const match = error ? null : page.pattern.exec(req.path);
|
||||||
|
|
||||||
Promise.all([root_preloaded].concat(page.parts.map(part => {
|
Promise.all([root_preloaded].concat(page.parts.map(part => {
|
||||||
if (!part) return null;
|
if (!part) return null;
|
||||||
|
|
||||||
@@ -582,4 +585,4 @@ function escape_html(html: string) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return html.replace(/["'&<>]/g, c => `&${chars[c]};`);
|
return html.replace(/["'&<>]/g, c => `&${chars[c]};`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,10 +136,6 @@ function prepare_page(target: Target): Promise<{
|
|||||||
data?: any;
|
data?: any;
|
||||||
nullable_depth?: number;
|
nullable_depth?: number;
|
||||||
}> {
|
}> {
|
||||||
if (root) {
|
|
||||||
root.set({ preloading: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
const { page, path, query } = target;
|
const { page, path, query } = target;
|
||||||
const new_segments = path.split('/').filter(Boolean);
|
const new_segments = path.split('/').filter(Boolean);
|
||||||
let changed_from = 0;
|
let changed_from = 0;
|
||||||
@@ -285,6 +281,9 @@ async function navigate(target: Target, id: number): Promise<any> {
|
|||||||
|
|
||||||
cid = id;
|
cid = id;
|
||||||
|
|
||||||
|
if (root) {
|
||||||
|
root.set({ preloading: true });
|
||||||
|
}
|
||||||
const loaded = prefetching && prefetching.href === target.url.href ?
|
const loaded = prefetching && prefetching.href === target.url.href ?
|
||||||
prefetching.promise :
|
prefetching.promise :
|
||||||
prepare_page(target);
|
prepare_page(target);
|
||||||
|
|||||||
@@ -85,11 +85,18 @@ const middlewares = [
|
|||||||
next();
|
next();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// set up some values for the store
|
||||||
|
(req, res, next) => {
|
||||||
|
req.hello = 'hello';
|
||||||
|
res.locals = { name: 'world' };
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
sapper({
|
sapper({
|
||||||
manifest,
|
manifest,
|
||||||
store: () => {
|
store: (req, res) => {
|
||||||
return new Store({
|
return new Store({
|
||||||
title: 'Stored title'
|
title: `${req.hello} ${res.locals.name}`
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
ignore: [
|
ignore: [
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<a href='about'>about</a>
|
<a href='about'>about</a>
|
||||||
<a href='slow-preload'>slow preload</a>
|
<a href='slow-preload'>slow preload</a>
|
||||||
<a href='redirect-from'>redirect</a>
|
<a href='redirect-from'>redirect</a>
|
||||||
|
<a href='redirect-root'>redirect (root)</a>
|
||||||
<a href='blog/nope'>broken link</a>
|
<a href='blog/nope'>broken link</a>
|
||||||
<a href='blog/throw-an-error'>error link</a>
|
<a href='blog/throw-an-error'>error link</a>
|
||||||
<a href='credentials?creds=include'>credentials</a>
|
<a href='credentials?creds=include'>credentials</a>
|
||||||
|
|||||||
7
test/app/routes/redirect-root.html
Normal file
7
test/app/routes/redirect-root.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
preload() {
|
||||||
|
this.redirect(301, '/');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -59,9 +59,19 @@ describe('sapper', function() {
|
|||||||
basepath: '/custom-basepath'
|
basepath: '/custom-basepath'
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('export', () => {
|
testExport({});
|
||||||
|
|
||||||
|
testExport({ basepath: '/custom-basepath' });
|
||||||
|
});
|
||||||
|
|
||||||
|
function testExport({ basepath = '' }) {
|
||||||
|
describe(basepath ? `export --basepath ${basepath}` : 'export', () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
return exec(`node ${cli} export`);
|
if (basepath) {
|
||||||
|
process.env.BASEPATH = basepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exec(`node ${cli} export ${basepath ? `--basepath ${basepath}` : ''}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('export all pages', () => {
|
it('export all pages', () => {
|
||||||
@@ -96,7 +106,10 @@ describe('sapper', function() {
|
|||||||
'service-worker.js',
|
'service-worker.js',
|
||||||
'svelte-logo-192.png',
|
'svelte-logo-192.png',
|
||||||
'svelte-logo-512.png',
|
'svelte-logo-512.png',
|
||||||
];
|
].map(file => {
|
||||||
|
return basepath ? `${basepath.replace(/^[\/\\]/, '')}/${file}` : file;
|
||||||
|
});
|
||||||
|
|
||||||
// Client scripts that should show up in the extraction directory.
|
// Client scripts that should show up in the extraction directory.
|
||||||
const expectedClientRegexes = [
|
const expectedClientRegexes = [
|
||||||
/client\/[^/]+\/main(\.\d+)?\.js/,
|
/client\/[^/]+\/main(\.\d+)?\.js/,
|
||||||
@@ -126,7 +139,7 @@ describe('sapper', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
function run({ mode, basepath = '' }) {
|
function run({ mode, basepath = '' }) {
|
||||||
describe(`mode=${mode}`, function () {
|
describe(`mode=${mode}`, function () {
|
||||||
@@ -423,6 +436,33 @@ function run({ mode, basepath = '' }) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('redirects on server (root)', () => {
|
||||||
|
return nightmare.goto(`${base}/redirect-root`)
|
||||||
|
.path()
|
||||||
|
.then(path => {
|
||||||
|
assert.equal(path, `${basepath}/`);
|
||||||
|
})
|
||||||
|
.then(() => nightmare.page.title())
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'Great success!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('redirects in client (root)', () => {
|
||||||
|
return nightmare.goto(base)
|
||||||
|
.wait('[href="redirect-root"]')
|
||||||
|
.click('[href="redirect-root"]')
|
||||||
|
.wait(200)
|
||||||
|
.path()
|
||||||
|
.then(path => {
|
||||||
|
assert.equal(path, `${basepath}/`);
|
||||||
|
})
|
||||||
|
.then(() => nightmare.page.title())
|
||||||
|
.then(title => {
|
||||||
|
assert.equal(title, 'Great success!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('handles 4xx error on server', () => {
|
it('handles 4xx error on server', () => {
|
||||||
return nightmare.goto(`${base}/blog/nope`)
|
return nightmare.goto(`${base}/blog/nope`)
|
||||||
.path()
|
.path()
|
||||||
@@ -568,11 +608,11 @@ function run({ mode, basepath = '' }) {
|
|||||||
return nightmare.goto(`${base}/store`)
|
return nightmare.goto(`${base}/store`)
|
||||||
.page.title()
|
.page.title()
|
||||||
.then(title => {
|
.then(title => {
|
||||||
assert.equal(title, 'Stored title');
|
assert.equal(title, 'hello world');
|
||||||
return nightmare.init().page.title();
|
return nightmare.init().page.title();
|
||||||
})
|
})
|
||||||
.then(title => {
|
.then(title => {
|
||||||
assert.equal(title, 'Stored title');
|
assert.equal(title, 'hello world');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
26
test/unit/clean_html/index.ts
Normal file
26
test/unit/clean_html/index.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import clean_html from '../../../src/api/utils/clean_html';
|
||||||
|
|
||||||
|
describe('clean_html', () => {
|
||||||
|
const samples = path.join(__dirname, 'samples');
|
||||||
|
|
||||||
|
fs.readdirSync(samples).forEach(dir => {
|
||||||
|
if (dir[0] === '.') return;
|
||||||
|
|
||||||
|
it(dir, () => {
|
||||||
|
const input = fs.readFileSync(`${samples}/${dir}/input.html`, 'utf-8');
|
||||||
|
const expected = fs.readFileSync(`${samples}/${dir}/output.html`, 'utf-8');
|
||||||
|
|
||||||
|
const actual = clean_html(input);
|
||||||
|
|
||||||
|
fs.writeFileSync(`${samples}/${dir}/.actual.html`, actual);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
actual.replace(/\s+$/gm, ''),
|
||||||
|
expected.replace(/\s+$/gm, '')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
14
test/unit/clean_html/samples/removes-cdata/.actual.html
Normal file
14
test/unit/clean_html/samples/removes-cdata/.actual.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<math>
|
||||||
|
<ms></ms>
|
||||||
|
<mo>+</mo>
|
||||||
|
<mn>3</mn>
|
||||||
|
<mo>=</mo>
|
||||||
|
<ms></ms>
|
||||||
|
</math>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
14
test/unit/clean_html/samples/removes-cdata/input.html
Normal file
14
test/unit/clean_html/samples/removes-cdata/input.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<math>
|
||||||
|
<ms><![CDATA[x<y]]></ms>
|
||||||
|
<mo>+</mo>
|
||||||
|
<mn>3</mn>
|
||||||
|
<mo>=</mo>
|
||||||
|
<ms><![CDATA[x<y3]]></ms>
|
||||||
|
</math>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
14
test/unit/clean_html/samples/removes-cdata/output.html
Normal file
14
test/unit/clean_html/samples/removes-cdata/output.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<math>
|
||||||
|
<ms></ms>
|
||||||
|
<mo>+</mo>
|
||||||
|
<mn>3</mn>
|
||||||
|
<mo>=</mo>
|
||||||
|
<ms></ms>
|
||||||
|
</math>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="keep-me">keep me</a>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
9
test/unit/clean_html/samples/removes-comments/input.html
Normal file
9
test/unit/clean_html/samples/removes-comments/input.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="keep-me">keep me</a>
|
||||||
|
<!-- <a href="delete-me">delete me</a> -->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="keep-me">keep me</a>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script></script>
|
||||||
|
|
||||||
|
<script></script>
|
||||||
|
|
||||||
|
<script src="attributes-are-preserved.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
console.log('this should be deleted');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
console.log('so should this');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script src="attributes-are-preserved.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script></script>
|
||||||
|
|
||||||
|
<script></script>
|
||||||
|
|
||||||
|
<script src="attributes-are-preserved.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
const path = require('path');
|
import * as path from 'path';
|
||||||
const assert = require('assert');
|
import * as assert from 'assert';
|
||||||
const { create_routes } = require('../../../dist/core.ts.js');
|
import create_routes from '../../../src/core/create_routes';
|
||||||
|
|
||||||
describe('create_routes', () => {
|
describe('create_routes', () => {
|
||||||
it('creates routes', () => {
|
it('creates routes', () => {
|
||||||
Reference in New Issue
Block a user