mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-19 05:45:27 +00:00
@@ -2,7 +2,7 @@
|
|||||||
"name": "sapper",
|
"name": "sapper",
|
||||||
"version": "0.9.3",
|
"version": "0.9.3",
|
||||||
"description": "Military-grade apps, engineered by Svelte",
|
"description": "Military-grade apps, engineered by Svelte",
|
||||||
"main": "middleware.js",
|
"main": "dist/middleware.ts.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"sapper": "./sapper"
|
"sapper": "./sapper"
|
||||||
},
|
},
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"clorox": "^1.0.3",
|
"clorox": "^1.0.3",
|
||||||
"devalue": "^1.0.1",
|
"devalue": "^1.0.1",
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
|
"html-minifier": "^3.5.10",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"node-fetch": "^1.7.3",
|
"node-fetch": "^1.7.3",
|
||||||
"polka": "^0.3.4",
|
"polka": "^0.3.4",
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import * as path from 'path';
|
|||||||
import * as clorox from 'clorox';
|
import * as clorox from 'clorox';
|
||||||
import mkdirp from 'mkdirp';
|
import mkdirp from 'mkdirp';
|
||||||
import rimraf from 'rimraf';
|
import rimraf from 'rimraf';
|
||||||
|
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 { dest } from '../config';
|
import { locations } from '../config';
|
||||||
|
|
||||||
export async function build() {
|
export async function build() {
|
||||||
const output = dest();
|
const output = locations.dest();
|
||||||
|
|
||||||
mkdirp.sync(output);
|
mkdirp.sync(output);
|
||||||
rimraf.sync(path.join(output, '**/*'));
|
rimraf.sync(path.join(output, '**/*'));
|
||||||
@@ -40,6 +41,11 @@ export async function build() {
|
|||||||
console.log(clorox.inverse(`\nbuilt service worker`).toString());
|
console.log(clorox.inverse(`\nbuilt service worker`).toString());
|
||||||
console.log(serviceworker_stats.toString({ colors: true }));
|
console.log(serviceworker_stats.toString({ colors: true }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// minify app/template.html
|
||||||
|
// TODO compile this to a function? could be quicker than str.replace(...).replace(...).replace(...)
|
||||||
|
const template = fs.readFileSync(`${locations.app()}/template.html`, 'utf-8');
|
||||||
|
fs.writeFileSync(`${output}/template.html`, minify_html(template));
|
||||||
}
|
}
|
||||||
|
|
||||||
function compile(compiler: any) {
|
function compile(compiler: any) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import rimraf from 'rimraf';
|
|||||||
import format_messages from 'webpack-format-messages';
|
import format_messages from 'webpack-format-messages';
|
||||||
import prettyMs from 'pretty-ms';
|
import prettyMs from 'pretty-ms';
|
||||||
import * as ports from 'port-authority';
|
import * as ports from 'port-authority';
|
||||||
import { dest } from '../config';
|
import { locations } from '../config';
|
||||||
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';
|
||||||
|
|
||||||
type Deferred = {
|
type Deferred = {
|
||||||
@@ -84,7 +84,7 @@ export async function dev(opts: { port: number }) {
|
|||||||
port = await ports.find(3000);
|
port = await ports.find(3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dir = dest();
|
const dir = locations.dest();
|
||||||
rimraf.sync(dir);
|
rimraf.sync(dir);
|
||||||
mkdirp.sync(dir);
|
mkdirp.sync(dir);
|
||||||
|
|
||||||
@@ -95,12 +95,12 @@ export async function dev(opts: { port: number }) {
|
|||||||
|
|
||||||
const hot_update_server = create_hot_update_server(dev_port);
|
const hot_update_server = create_hot_update_server(dev_port);
|
||||||
|
|
||||||
watch_files('routes/**/*', ['add', 'unlink'], () => {
|
watch_files(`${locations.routes()}/**/*`, ['add', 'unlink'], () => {
|
||||||
const routes = create_routes();
|
const routes = create_routes();
|
||||||
create_main_manifests({ routes, dev_port });
|
create_main_manifests({ routes, dev_port });
|
||||||
});
|
});
|
||||||
|
|
||||||
watch_files('app/template.html', ['change'], () => {
|
watch_files(`${locations.app()}/template.html`, ['change'], () => {
|
||||||
hot_update_server.send({
|
hot_update_server.send({
|
||||||
action: 'reload'
|
action: 'reload'
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ 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 { dest } from '../config';
|
import { locations } from '../config';
|
||||||
|
|
||||||
export async function exporter(export_dir: string) {
|
export async function exporter(export_dir: string) {
|
||||||
const build_dir = dest();
|
const build_dir = locations.dest();
|
||||||
|
|
||||||
// Prep output directory
|
// Prep output directory
|
||||||
sander.rimrafSync(export_dir);
|
sander.rimrafSync(export_dir);
|
||||||
|
|||||||
21
src/cli/utils/minify_html.ts
Normal file
21
src/cli/utils/minify_html.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { minify } from 'html-minifier';
|
||||||
|
|
||||||
|
export function minify_html(html: string) {
|
||||||
|
return minify(html, {
|
||||||
|
collapseBooleanAttributes: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
conservativeCollapse: true,
|
||||||
|
decodeEntities: true,
|
||||||
|
html5: true,
|
||||||
|
minifyCSS: true,
|
||||||
|
minifyJS: true,
|
||||||
|
removeAttributeQuotes: true,
|
||||||
|
removeComments: true,
|
||||||
|
removeOptionalTags: true,
|
||||||
|
removeRedundantAttributes: true,
|
||||||
|
removeScriptTypeAttributes: true,
|
||||||
|
removeStyleLinkTypeAttributes: true,
|
||||||
|
sortAttributes: true,
|
||||||
|
sortClassName: true
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
export const dev = () => process.env.NODE_ENV !== 'production';
|
export const dev = () => process.env.NODE_ENV !== 'production';
|
||||||
export const src = () => path.resolve(process.env.SAPPER_ROUTES || 'routes');
|
|
||||||
export const dest = () => path.resolve(process.env.SAPPER_DEST || '.sapper');
|
export const locations = {
|
||||||
|
base: () => path.resolve(process.env.SAPPER_BASE || ''),
|
||||||
|
app: () => path.resolve(process.env.SAPPER_BASE || '', process.env.SAPPER_APP || 'app'),
|
||||||
|
routes: () => path.resolve(process.env.SAPPER_BASE || '', process.env.SAPPER_ROUTES || 'routes'),
|
||||||
|
dest: () => path.resolve(process.env.SAPPER_BASE || '', process.env.SAPPER_DEST || '.sapper')
|
||||||
|
};
|
||||||
@@ -3,18 +3,20 @@ import * as path from 'path';
|
|||||||
import * as glob from 'glob';
|
import * as glob from 'glob';
|
||||||
import create_routes from './create_routes';
|
import create_routes from './create_routes';
|
||||||
import { posixify, write_if_changed } from './utils';
|
import { posixify, write_if_changed } from './utils';
|
||||||
import { dev } from '../config';
|
import { dev, locations } from '../config';
|
||||||
import { Route } from '../interfaces';
|
import { Route } from '../interfaces';
|
||||||
|
|
||||||
export function create_main_manifests({ routes, dev_port }: {
|
export function create_main_manifests({ routes, dev_port }: {
|
||||||
routes: Route[];
|
routes: Route[];
|
||||||
dev_port?: number;
|
dev_port?: number;
|
||||||
}) {
|
}) {
|
||||||
const client_manifest = generate_client(routes, dev_port);
|
const path_to_routes = path.relative(`${locations.app()}/manifest`, locations.routes());
|
||||||
const server_manifest = generate_server(routes);
|
|
||||||
|
|
||||||
write_if_changed(`app/manifest/client.js`, client_manifest);
|
const client_manifest = generate_client(routes, path_to_routes, dev_port);
|
||||||
write_if_changed(`app/manifest/server.js`, server_manifest);
|
const server_manifest = generate_server(routes, path_to_routes);
|
||||||
|
|
||||||
|
write_if_changed(`${locations.app()}/manifest/client.js`, client_manifest);
|
||||||
|
write_if_changed(`${locations.app()}/manifest/server.js`, server_manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function create_serviceworker_manifest({ routes, client_files }: {
|
export function create_serviceworker_manifest({ routes, client_files }: {
|
||||||
@@ -34,10 +36,10 @@ export function create_serviceworker_manifest({ routes, client_files }: {
|
|||||||
export const routes = [\n\t${routes.filter((r: Route) => r.type === 'page' && !/^_[45]xx$/.test(r.id)).map((r: Route) => `{ pattern: ${r.pattern} }`).join(',\n\t')}\n];
|
export const routes = [\n\t${routes.filter((r: Route) => r.type === 'page' && !/^_[45]xx$/.test(r.id)).map((r: Route) => `{ pattern: ${r.pattern} }`).join(',\n\t')}\n];
|
||||||
`.replace(/^\t\t/gm, '').trim();
|
`.replace(/^\t\t/gm, '').trim();
|
||||||
|
|
||||||
write_if_changed('app/manifest/service-worker.js', code);
|
write_if_changed(`${locations.app()}/manifest/service-worker.js`, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generate_client(routes: Route[], dev_port?: number) {
|
function generate_client(routes: Route[], path_to_routes: string, dev_port?: number) {
|
||||||
let code = `
|
let code = `
|
||||||
// This file is generated by Sapper — do not edit it!
|
// This file is generated by Sapper — do not edit it!
|
||||||
export const routes = [
|
export const routes = [
|
||||||
@@ -47,7 +49,7 @@ function generate_client(routes: Route[], dev_port?: number) {
|
|||||||
return `{ pattern: ${route.pattern}, ignore: true }`;
|
return `{ pattern: ${route.pattern}, ignore: true }`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = posixify(`../../routes/${route.file}`);
|
const file = posixify(`${path_to_routes}/${route.file}`);
|
||||||
|
|
||||||
if (route.id === '_4xx' || route.id === '_5xx') {
|
if (route.id === '_4xx' || route.id === '_5xx') {
|
||||||
return `{ error: '${route.id.slice(1)}', load: () => import(/* webpackChunkName: "${route.id}" */ '${file}') }`;
|
return `{ error: '${route.id.slice(1)}', load: () => import(/* webpackChunkName: "${route.id}" */ '${file}') }`;
|
||||||
@@ -79,12 +81,12 @@ function generate_client(routes: Route[], dev_port?: number) {
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generate_server(routes: Route[]) {
|
function generate_server(routes: Route[], path_to_routes: string) {
|
||||||
let code = `
|
let code = `
|
||||||
// This file is generated by Sapper — do not edit it!
|
// This file is generated by Sapper — do not edit it!
|
||||||
${routes
|
${routes
|
||||||
.map(route => {
|
.map(route => {
|
||||||
const file = posixify(`../../routes/${route.file}`);
|
const file = posixify(`${path_to_routes}/${route.file}`);
|
||||||
return route.type === 'page'
|
return route.type === 'page'
|
||||||
? `import ${route.id} from '${file}';`
|
? `import ${route.id} from '${file}';`
|
||||||
: `import * as ${route.id} from '${file}';`;
|
: `import * as ${route.id} from '${file}';`;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import glob from 'glob';
|
import glob from 'glob';
|
||||||
import { src } from '../config';
|
import { locations } from '../config';
|
||||||
import { Route } from '../interfaces';
|
import { Route } from '../interfaces';
|
||||||
|
|
||||||
export default function create_routes({ files } = { files: glob.sync('**/*.*', { cwd: src(), nodir: true }) }) {
|
export default function create_routes({ files } = { files: glob.sync('**/*.*', { cwd: locations.routes(), nodir: true }) }) {
|
||||||
const routes: Route[] = files
|
const routes: Route[] = files
|
||||||
.map((file: string) => {
|
.map((file: string) => {
|
||||||
if (/(^|\/|\\)_/.test(file)) return;
|
if (/(^|\/|\\)_/.test(file)) return;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import rimraf from 'rimraf';
|
|||||||
import devalue from 'devalue';
|
import devalue from 'devalue';
|
||||||
import { lookup } from './middleware/mime';
|
import { lookup } from './middleware/mime';
|
||||||
import { create_routes, create_compilers } from './core';
|
import { create_routes, create_compilers } from './core';
|
||||||
import { dest, dev } from './config';
|
import { locations, dev } from './config';
|
||||||
import { Route, Template } from './interfaces';
|
import { Route, Template } from './interfaces';
|
||||||
import sourceMapSupport from 'source-map-support';
|
import sourceMapSupport from 'source-map-support';
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ interface Req extends ClientRequest {
|
|||||||
export default function middleware({ routes }: {
|
export default function middleware({ routes }: {
|
||||||
routes: RouteObject[]
|
routes: RouteObject[]
|
||||||
}) {
|
}) {
|
||||||
const output = dest();
|
const output = locations.dest();
|
||||||
|
|
||||||
const client_info = JSON.parse(fs.readFileSync(path.join(output, 'client_info.json'), 'utf-8'));
|
const client_info = JSON.parse(fs.readFileSync(path.join(output, 'client_info.json'), 'utf-8'));
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ function serve({ prefix, pathname, cache_control }: {
|
|||||||
? (req: Req) => req.pathname === pathname
|
? (req: Req) => req.pathname === pathname
|
||||||
: (req: Req) => req.pathname.startsWith(prefix);
|
: (req: Req) => req.pathname.startsWith(prefix);
|
||||||
|
|
||||||
const output = dest();
|
const output = locations.dest();
|
||||||
|
|
||||||
const cache: Map<string, Buffer> = new Map();
|
const cache: Map<string, Buffer> = new Map();
|
||||||
|
|
||||||
@@ -112,8 +112,8 @@ const resolved = Promise.resolve();
|
|||||||
|
|
||||||
function get_route_handler(chunks: Record<string, string>, routes: RouteObject[]) {
|
function get_route_handler(chunks: Record<string, string>, routes: RouteObject[]) {
|
||||||
const template = dev()
|
const template = dev()
|
||||||
? () => fs.readFileSync('app/template.html', 'utf-8')
|
? () => fs.readFileSync(`${locations.app()}/template.html`, 'utf-8')
|
||||||
: (str => () => str)(fs.readFileSync('app/template.html', 'utf-8'));
|
: (str => () => str)(fs.readFileSync(`${locations.dest()}/template.html`, 'utf-8'));
|
||||||
|
|
||||||
function handle_route(route: RouteObject, req: Req, res: ServerResponse) {
|
function handle_route(route: RouteObject, req: Req, res: ServerResponse) {
|
||||||
req.params = route.params(route.pattern.exec(req.pathname));
|
req.params = route.params(route.pattern.exec(req.pathname));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { dest, dev } from './config';
|
import { locations, dev } from './config';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
dev: dev(),
|
dev: dev(),
|
||||||
@@ -6,13 +6,13 @@ export default {
|
|||||||
client: {
|
client: {
|
||||||
entry: () => {
|
entry: () => {
|
||||||
return {
|
return {
|
||||||
main: './app/client'
|
main: `${locations.app()}/client`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
output: () => {
|
output: () => {
|
||||||
return {
|
return {
|
||||||
path: `${dest()}/client`,
|
path: `${locations.dest()}/client`,
|
||||||
filename: '[hash]/[name].js',
|
filename: '[hash]/[name].js',
|
||||||
chunkFilename: '[hash]/[name].[id].js',
|
chunkFilename: '[hash]/[name].[id].js',
|
||||||
publicPath: '/client/'
|
publicPath: '/client/'
|
||||||
@@ -23,13 +23,13 @@ export default {
|
|||||||
server: {
|
server: {
|
||||||
entry: () => {
|
entry: () => {
|
||||||
return {
|
return {
|
||||||
server: './app/server'
|
server: `${locations.app()}/server`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
output: () => {
|
output: () => {
|
||||||
return {
|
return {
|
||||||
path: dest(),
|
path: locations.dest(),
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
chunkFilename: '[hash]/[name].[id].js',
|
chunkFilename: '[hash]/[name].[id].js',
|
||||||
libraryTarget: 'commonjs2'
|
libraryTarget: 'commonjs2'
|
||||||
@@ -40,13 +40,13 @@ export default {
|
|||||||
serviceworker: {
|
serviceworker: {
|
||||||
entry: () => {
|
entry: () => {
|
||||||
return {
|
return {
|
||||||
'service-worker': './app/service-worker'
|
'service-worker': `${locations.app()}/service-worker`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
output: () => {
|
output: () => {
|
||||||
return {
|
return {
|
||||||
path: dest(),
|
path: locations.dest(),
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
chunkFilename: '[name].[id].[hash].js'
|
chunkFilename: '[name].[id].[hash].js'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user