diff --git a/.gitignore b/.gitignore index 81c2c19..216e636 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ node_modules .sapper yarn.lock cypress/screenshots -templates/.* \ No newline at end of file +templates/.* +export +build +app/manifest \ No newline at end of file diff --git a/app/client.js b/app/client.js new file mode 100644 index 0000000..05d30aa --- /dev/null +++ b/app/client.js @@ -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(); \ No newline at end of file diff --git a/app/server.js b/app/server.js new file mode 100644 index 0000000..0af7864 --- /dev/null +++ b/app/server.js @@ -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}`); +}); \ No newline at end of file diff --git a/templates/service-worker.js b/app/service-worker.js similarity index 84% rename from templates/service-worker.js rename to app/service-worker.js index cccb12a..dca8106 100644 --- a/templates/service-worker.js +++ b/app/service-worker.js @@ -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; } diff --git a/templates/2xx.html b/app/template.html similarity index 100% rename from templates/2xx.html rename to app/template.html diff --git a/package.json b/package.json index 4d601e8..98ce2af 100644 --- a/package.json +++ b/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" } } diff --git a/routes/4xx.html b/routes/4xx.html new file mode 100644 index 0000000..0a98eb7 --- /dev/null +++ b/routes/4xx.html @@ -0,0 +1,43 @@ +<:Head> +
Please check the URL
+routes/blog/[slug].htmlroutes directory. These are just .js files that export functions corresponding to HTTP methods, and receive Express request and response 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 routes/api/blog)routes directory. These are just .js files that export functions corresponding to HTTP methods, and receive Express request and response objects as arguments. This makes it very easy to, for example, add a JSON API such as the one powering this very page<a> elements, rather than framework-specific <Link> components. That means, for example, that this link right here, despite being inside a blob of HTML, works with the router as you'd expect.
+
Could not %sapper.method% %sapper.url%
- - %sapper.scripts% - - \ No newline at end of file diff --git a/templates/5xx.html b/templates/5xx.html deleted file mode 100644 index 357152d..0000000 --- a/templates/5xx.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - -%sapper.error%-
%sapper.stack%- - \ No newline at end of file diff --git a/templates/main.js b/templates/main.js deleted file mode 100644 index aa08cb0..0000000 --- a/templates/main.js +++ /dev/null @@ -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__); \ No newline at end of file diff --git a/webpack.client.config.js b/webpack.client.config.js deleted file mode 100644 index 904aa06..0000000 --- a/webpack.client.config.js +++ /dev/null @@ -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' -}; diff --git a/webpack/client.config.js b/webpack/client.config.js new file mode 100644 index 0000000..b8798da --- /dev/null +++ b/webpack/client.config.js @@ -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' +}; diff --git a/webpack.server.config.js b/webpack/server.config.js similarity index 64% rename from webpack.server.config.js rename to webpack/server.config.js index 97a977c..e400d67 100644 --- a/webpack.server.config.js +++ b/webpack/server.config.js @@ -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 } }; \ No newline at end of file diff --git a/webpack/service-worker.config.js b/webpack/service-worker.config.js new file mode 100644 index 0000000..5e086a9 --- /dev/null +++ b/webpack/service-worker.config.js @@ -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 +}; \ No newline at end of file