mirror of
https://github.com/kevin-DL/sapper-template.git
synced 2026-01-12 02:15:17 +00:00
Merge branch 'master' into chore/remove-dependencies
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -3,4 +3,7 @@ node_modules
|
||||
.sapper
|
||||
yarn.lock
|
||||
cypress/screenshots
|
||||
templates/.*
|
||||
templates/.*
|
||||
export
|
||||
build
|
||||
app/manifest
|
||||
7
app/client.js
Normal file
7
app/client.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { init } from 'sapper/runtime.js';
|
||||
import { routes } from './manifest/client.js';
|
||||
|
||||
// `routes` is an array of route objects injected by Sapper
|
||||
init(document.querySelector('#sapper'), routes);
|
||||
|
||||
if (module.hot) module.hot.accept();
|
||||
29
app/server.js
Normal file
29
app/server.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import fs from 'fs';
|
||||
import express from 'express';
|
||||
import compression from 'compression';
|
||||
import sapper from 'sapper';
|
||||
import serve from 'serve-static';
|
||||
import fetch from 'node-fetch';
|
||||
import { routes } from './manifest/server.js';
|
||||
|
||||
const app = express();
|
||||
|
||||
const { PORT = 3000 } = process.env;
|
||||
|
||||
// this allows us to do e.g. `fetch('/api/blog-posts')` on the server
|
||||
global.fetch = (url, opts) => {
|
||||
if (url[0] === '/') url = `http://localhost:${PORT}${url}`;
|
||||
return fetch(url, opts);
|
||||
};
|
||||
|
||||
app.use(compression({ threshold: 0 }));
|
||||
|
||||
app.use(serve('assets'));
|
||||
|
||||
app.use(sapper({
|
||||
routes
|
||||
}));
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`listening on port ${PORT}`);
|
||||
});
|
||||
@@ -1,15 +1,12 @@
|
||||
const timestamp = '__timestamp__';
|
||||
import { timestamp, assets, shell, routes } from './manifest/service-worker.js';
|
||||
|
||||
const ASSETS = `cache${timestamp}`;
|
||||
|
||||
// `shell` is an array of all the files generated by webpack,
|
||||
// `assets` is an array of everything in the `assets` directory
|
||||
const to_cache = __shell__.concat(__assets__);
|
||||
const to_cache = shell.concat(assets);
|
||||
const cached = new Set(to_cache);
|
||||
|
||||
// `routes` is an array of `{ pattern: RegExp }` objects that
|
||||
// match the pages in your app
|
||||
const routes = __routes__;
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
@@ -29,7 +26,7 @@ self.addEventListener('activate', event => {
|
||||
if (key !== ASSETS) await caches.delete(key);
|
||||
}
|
||||
|
||||
await self.clients.claim();
|
||||
self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -40,8 +37,11 @@ self.addEventListener('fetch', event => {
|
||||
// don't try to handle e.g. data: URIs
|
||||
if (!url.protocol.startsWith('http')) return;
|
||||
|
||||
// ignore dev server requests
|
||||
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
|
||||
|
||||
// always serve assets and webpack-generated files from cache
|
||||
if (cached.has(url.pathname)) {
|
||||
if (url.host === self.location.host && cached.has(url.pathname)) {
|
||||
event.respondWith(caches.match(event.request));
|
||||
return;
|
||||
}
|
||||
18
package.json
18
package.json
@@ -3,9 +3,10 @@
|
||||
"description": "TODO",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "node server.js",
|
||||
"dev": "sapper dev",
|
||||
"build": "sapper build",
|
||||
"start": "cross-env NODE_ENV=production node server.js",
|
||||
"export": "sapper export",
|
||||
"start": "sapper start",
|
||||
"cy:run": "cypress run",
|
||||
"cy:open": "cypress open",
|
||||
"test": "run-p --race dev cy:run"
|
||||
@@ -13,16 +14,13 @@
|
||||
"dependencies": {
|
||||
"compression": "^1.7.1",
|
||||
"cross-env": "^5.1.3",
|
||||
"css-loader": "^0.28.7",
|
||||
"express": "^4.16.2",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"node-fetch": "^1.7.3",
|
||||
"sapper": "^0.5.0",
|
||||
"node-fetch": "^2.0.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"sapper": "^0.8.1",
|
||||
"serve-static": "^1.13.1",
|
||||
"style-loader": "^0.19.1",
|
||||
"svelte": "^1.51.1",
|
||||
"svelte": "^1.56.0",
|
||||
"svelte-loader": "^2.3.3",
|
||||
"uglifyjs-webpack-plugin": "^1.1.5",
|
||||
"webpack": "^3.10.0"
|
||||
"webpack": "^4.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
43
routes/4xx.html
Normal file
43
routes/4xx.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<:Head>
|
||||
<title>Not found</title>
|
||||
</:Head>
|
||||
|
||||
<Layout page='home'>
|
||||
<h1>Not found</h1>
|
||||
|
||||
<p>Please check the URL</p>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
h1, p {
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.8em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 1em auto;
|
||||
}
|
||||
|
||||
@media (min-width: 480px) {
|
||||
h1 {
|
||||
font-size: 4em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Layout from './_components/Layout.html';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Layout
|
||||
}
|
||||
};
|
||||
</script>
|
||||
34
routes/5xx.html
Normal file
34
routes/5xx.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<:Head>
|
||||
<title>Internal server error</title>
|
||||
</:Head>
|
||||
|
||||
<Layout page='home'>
|
||||
<h1>Internal server error</h1>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
font-size: 2.8em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
@media (min-width: 480px) {
|
||||
h1 {
|
||||
font-size: 4em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Layout from './_components/Layout.html';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Layout
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,4 +1,4 @@
|
||||
import posts from './_posts.js';
|
||||
import posts from './blog/_posts.js';
|
||||
|
||||
const contents = JSON.stringify(posts.map(post => {
|
||||
return {
|
||||
@@ -59,7 +59,7 @@
|
||||
// is called [slug].html
|
||||
const { slug } = params;
|
||||
|
||||
return fetch(`/api/blog/${slug}`).then(r => r.json()).then(post => {
|
||||
return fetch(`/blog/${slug}.json`).then(r => r.json()).then(post => {
|
||||
return { post };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ posts.forEach(post => {
|
||||
|
||||
export function get(req, res, next) {
|
||||
// the `slug` parameter is available because this file
|
||||
// is called [slug].js
|
||||
// is called [slug].json.js
|
||||
const { slug } = req.params;
|
||||
|
||||
if (lookup.has(slug)) {
|
||||
@@ -4,7 +4,7 @@
|
||||
// service of obviousness, we're just going to leave it here.
|
||||
|
||||
// This file is called `_posts.js` rather than `posts.js`, because
|
||||
// we don't want to create an `/api/blog/posts` route — the leading
|
||||
// we don't want to create an `/blog/posts` route — the leading
|
||||
// underscore tells Sapper not to do that.
|
||||
|
||||
const posts = [
|
||||
@@ -70,7 +70,7 @@ const posts = [
|
||||
<ul>
|
||||
<li>It's powered by <a href='https://svelte.technology'>Svelte</a> instead of React, so it's faster and your apps are smaller</li>
|
||||
<li>Instead of route masking, we encode route parameters in filenames. For example, the page you're looking at right now is <code>routes/blog/[slug].html</code></li>
|
||||
<li>As well as pages (Svelte components, which render on server or client), you can create <em>server routes</em> in your <code>routes</code> directory. These are just <code>.js</code> files that export functions corresponding to HTTP methods, and receive Express <code>request</code> and <code>response</code> objects as arguments. This makes it very easy to, for example, add a JSON API such as the one powering this very page (look in <code>routes/api/blog</code>)</li>
|
||||
<li>As well as pages (Svelte components, which render on server or client), you can create <em>server routes</em> in your <code>routes</code> directory. These are just <code>.js</code> files that export functions corresponding to HTTP methods, and receive Express <code>request</code> and <code>response</code> objects as arguments. This makes it very easy to, for example, add a JSON API such as the one <a href='/blog/how-is-sapper-different-from-next.json'>powering this very page</a></li>
|
||||
<li>Links are just <code><a></code> elements, rather than framework-specific <code><Link></code> components. That means, for example, that <a href='/blog/how-can-i-get-involved'>this link right here</a>, despite being inside a blob of HTML, works with the router as you'd expect.</li>
|
||||
</ul>
|
||||
`
|
||||
@@ -32,7 +32,7 @@
|
||||
},
|
||||
|
||||
preload({ params, query }) {
|
||||
return fetch(`/api/blog`).then(r => r.json()).then(posts => {
|
||||
return fetch(`/blog.json`).then(r => r.json()).then(posts => {
|
||||
return { posts };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h1>Great success!</h1>
|
||||
|
||||
<figure>
|
||||
<img src='/great-success.png'>
|
||||
<img alt='Borat' src='/great-success.png'>
|
||||
<figcaption>HIGH FIVE!</figcaption>
|
||||
</figure>
|
||||
|
||||
|
||||
24
server.js
24
server.js
@@ -1,24 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const app = require('express')();
|
||||
const compression = require('compression');
|
||||
const sapper = require('sapper');
|
||||
const static = require('serve-static');
|
||||
|
||||
const { PORT = 3000 } = process.env;
|
||||
|
||||
// this allows us to do e.g. `fetch('/api/blog')` on the server
|
||||
const fetch = require('node-fetch');
|
||||
global.fetch = (url, opts) => {
|
||||
if (url[0] === '/') url = `http://localhost:${PORT}${url}`;
|
||||
return fetch(url, opts);
|
||||
};
|
||||
|
||||
app.use(compression({ threshold: 0 }));
|
||||
|
||||
app.use(static('assets'));
|
||||
|
||||
app.use(sapper());
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`listening on port ${PORT}`);
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
<meta name='theme-color' content='#aa1e1e'>
|
||||
|
||||
<link rel='manifest' href='/manifest.json'>
|
||||
<link rel='icon' type='image/png' href='/favicon.png'>
|
||||
|
||||
<!-- %sapper.status% is the HTTP status code, e.g. 404 -->
|
||||
<title>%sapper.status%</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
max-width: 800px;
|
||||
padding: 1em;
|
||||
margin: 0 auto;
|
||||
font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: rgb(170,30,30);
|
||||
border-bottom: 1px solid #aaa;
|
||||
padding: 0 0 0.5em 0;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: Menlo, monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.2;
|
||||
overflow-x: auto;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>%sapper.title%</h1>
|
||||
<p>Could not %sapper.method% %sapper.url%</p>
|
||||
|
||||
%sapper.scripts%
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,47 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
<meta name='theme-color' content='#aa1e1e'>
|
||||
|
||||
<link rel='manifest' href='/manifest.json'>
|
||||
<link rel='icon' type='image/png' href='/favicon.png'>
|
||||
|
||||
<title>%sapper.status%</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
max-width: 800px;
|
||||
padding: 1em;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: rgb(170,30,30);
|
||||
border-bottom: 1px solid #aaa;
|
||||
padding: 0 0 0.5em 0;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: Menlo, monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.2;
|
||||
overflow-x: auto;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.stack {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>%sapper.title%</h1>
|
||||
<pre>%sapper.error%</pre>
|
||||
<pre class='stack'>%sapper.stack%</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +0,0 @@
|
||||
import { init } from 'sapper/runtime.js';
|
||||
|
||||
// `routes` is an array of route objects injected by Sapper
|
||||
init(document.querySelector('#sapper'), __routes__);
|
||||
@@ -1,59 +0,0 @@
|
||||
const webpack = require('webpack');
|
||||
const config = require('sapper/webpack/config.js');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
||||
|
||||
const isDev = config.dev;
|
||||
|
||||
module.exports = {
|
||||
entry: config.client.entry(),
|
||||
output: config.client.output(),
|
||||
resolve: {
|
||||
extensions: ['.js', '.html']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.html$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'svelte-loader',
|
||||
options: {
|
||||
hydratable: true,
|
||||
emitCss: !isDev,
|
||||
cascade: false,
|
||||
store: true
|
||||
}
|
||||
}
|
||||
},
|
||||
isDev && {
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
{ loader: 'style-loader' },
|
||||
{ loader: 'css-loader' }
|
||||
]
|
||||
},
|
||||
!isDev && {
|
||||
test: /\.css$/,
|
||||
use: ExtractTextPlugin.extract({
|
||||
fallback: 'style-loader',
|
||||
use: [{ loader: 'css-loader', options: { sourceMap:isDev } }]
|
||||
})
|
||||
}
|
||||
].filter(Boolean)
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
minChunks: 2,
|
||||
async: false,
|
||||
children: true
|
||||
})
|
||||
].concat(isDev ? [
|
||||
new webpack.HotModuleReplacementPlugin()
|
||||
] : [
|
||||
new ExtractTextPlugin('main.css'),
|
||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||
new UglifyJSPlugin()
|
||||
]).filter(Boolean),
|
||||
devtool: isDev && 'inline-source-map'
|
||||
};
|
||||
39
webpack/client.config.js
Normal file
39
webpack/client.config.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const webpack = require('webpack');
|
||||
const config = require('sapper/webpack/config.js');
|
||||
|
||||
const mode = process.env.NODE_ENV;
|
||||
const isDev = mode === 'development';
|
||||
|
||||
module.exports = {
|
||||
entry: config.client.entry(),
|
||||
output: config.client.output(),
|
||||
resolve: {
|
||||
extensions: ['.js', '.json', '.html']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.html$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'svelte-loader',
|
||||
options: {
|
||||
hydratable: true,
|
||||
cascade: false,
|
||||
store: true,
|
||||
hotReload: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
mode,
|
||||
plugins: [
|
||||
isDev && new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.browser': true,
|
||||
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||
}),
|
||||
].filter(Boolean),
|
||||
devtool: isDev && 'inline-source-map'
|
||||
};
|
||||
@@ -1,15 +1,14 @@
|
||||
const config = require('sapper/webpack/config.js');
|
||||
const webpack = require('webpack');
|
||||
const ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
||||
const pkg = require('../package.json');
|
||||
|
||||
module.exports = {
|
||||
entry: config.server.entry(),
|
||||
output: config.server.output(),
|
||||
target: 'node',
|
||||
resolve: {
|
||||
extensions: ['.js', '.html']
|
||||
extensions: ['.js', '.json', '.html']
|
||||
},
|
||||
externals: Object.keys(pkg.dependencies),
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
@@ -26,5 +25,9 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
mode: process.env.NODE_ENV,
|
||||
performance: {
|
||||
hints: false // it doesn't matter if server.js is large
|
||||
}
|
||||
};
|
||||
7
webpack/service-worker.config.js
Normal file
7
webpack/service-worker.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const config = require('sapper/webpack/config.js');
|
||||
|
||||
module.exports = {
|
||||
entry: config.serviceworker.entry(),
|
||||
output: config.serviceworker.output(),
|
||||
mode: process.env.NODE_ENV
|
||||
};
|
||||
Reference in New Issue
Block a user