diff --git a/examples/routify/.gitignore b/examples/routify/.gitignore
index 1b1141140d..0c2147c3be 100644
--- a/examples/routify/.gitignore
+++ b/examples/routify/.gitignore
@@ -1,6 +1,9 @@
-/node_modules
-/dist
+**/node_modules/
+/dist/
.DS_Store
+**/.history
+src/tmp/
.routify
-yarn-debug.log*
-yarn-error.log*
\ No newline at end of file
+.netlify
+assets/build
+.vercel
diff --git a/examples/routify/.nolluprc.js b/examples/routify/.nolluprc.js
new file mode 100644
index 0000000000..5a5197fdc9
--- /dev/null
+++ b/examples/routify/.nolluprc.js
@@ -0,0 +1,7 @@
+module.exports = {
+ hot: true,
+ contentBase: 'assets',
+ publicPath: 'build',
+ historyApiFallback: '__app.html',
+ port: 5000
+}
diff --git a/examples/routify/api/netlify/package.json b/examples/routify/api/netlify/package.json
new file mode 100644
index 0000000000..e11c9fcb11
--- /dev/null
+++ b/examples/routify/api/netlify/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "ssr",
+ "version": "1.0.0",
+ "description": "",
+ "main": "ssr.js",
+ "scripts": {
+ "build": "node utils/build.js",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "esbuild": "^0.8.8",
+ "tossr": "^1.3.1"
+ }
+}
diff --git a/examples/routify/api/netlify/ssr.js b/examples/routify/api/netlify/ssr.js
new file mode 100644
index 0000000000..bef24828c0
--- /dev/null
+++ b/examples/routify/api/netlify/ssr.js
@@ -0,0 +1,11 @@
+const fs = require('fs')
+const { tossr } = require('tossr')
+const { script, template } = require('./bundle.json')
+
+exports.handler = async (event, context) => {
+ const qs = Object.entries(event.queryStringParameters)
+ .map(([key, value]) => `${key}=${value}`)
+ .join('&');
+ const body = await tossr(template, script, `${event.path}?${qs}`);
+ return { statusCode: 200, body: body + '\n' }
+}
diff --git a/examples/routify/api/netlify/utils/build.js b/examples/routify/api/netlify/utils/build.js
new file mode 100644
index 0000000000..4b620a22b8
--- /dev/null
+++ b/examples/routify/api/netlify/utils/build.js
@@ -0,0 +1,26 @@
+/**
+ * Creates a JSON and inlines it with esbuild for ssr.js to consume
+ * {
+ * data: duh,
+ * script: inlined main.js
+ * template: __app.html
+ * }
+ */
+
+const { resolve } = require('path')
+const { readFileSync, writeFileSync } = require('fs')
+const { build } = require('esbuild')
+
+const scriptPath = resolve(__dirname, '../../../dist/build/main.js')
+const templatePath = resolve(__dirname, '../../../dist/__app.html')
+const bundlePath = resolve(__dirname, '../build/bundle.js')
+
+build({ entryPoints: [scriptPath], outfile: bundlePath, bundle: true }).then(() => {
+ const bundle = {
+ date: new Date,
+ script: readFileSync(bundlePath, 'utf8'),
+ template: readFileSync(templatePath, 'utf8')
+ }
+
+ writeFileSync(resolve(__dirname, '../bundle.json'), JSON.stringify(bundle, null, 2))
+})
diff --git a/examples/routify/api/vercel-ssr/build.js b/examples/routify/api/vercel-ssr/build.js
new file mode 100644
index 0000000000..4fd54ba2db
--- /dev/null
+++ b/examples/routify/api/vercel-ssr/build.js
@@ -0,0 +1,36 @@
+const { resolve } = require('path')
+const { existsSync } = require('fs')
+const { execSync } = require('child_process')
+const { rollup } = require('rollup')
+
+const shouldBuildSpa = process.env.NOW_GITHUB_DEPLOYMENT || process.env.NOW_BUILDER
+const script = resolve(__dirname, '../../dist/build/main.js')
+const bundlePath = resolve(__dirname, '../../dist/build/bundle.js')
+
+build()
+
+
+async function build() {
+ if (shouldBuildSpa)
+ execSync('npm install && npm run build:app', { cwd: resolve('..', '..'), stdio: 'inherit' })
+ else
+ await waitForAppToExist()
+
+ buildSSRBundle()
+}
+
+async function waitForAppToExist() {
+ while (!existsSync(script)) {
+ console.log(`checking if "${script}" exists`)
+ await new Promise(r => setTimeout(r, 2000))
+ }
+ console.log(`found "${script}"`)
+}
+
+async function buildSSRBundle() {
+ const bundle = await rollup({
+ input: script,
+ inlineDynamicImports: true,
+ })
+ await bundle.write({ format: 'umd', file: bundlePath, name: 'roxi-ssr' })
+}
diff --git a/examples/routify/api/vercel-ssr/index.js b/examples/routify/api/vercel-ssr/index.js
new file mode 100644
index 0000000000..1b8afa4fa1
--- /dev/null
+++ b/examples/routify/api/vercel-ssr/index.js
@@ -0,0 +1,11 @@
+const fs = require('fs')
+const { tossr } = require('tossr')
+
+const script = fs.readFileSync(require.resolve('../../dist/build/bundle.js'), 'utf8')
+const template = fs.readFileSync(require.resolve('../../dist/__app.html'), 'utf8')
+
+module.exports = async (req, res) => {
+ const html = await tossr(template, script, req.url, {})
+ res.send(html + '\n')
+}
+
diff --git a/examples/routify/api/vercel-ssr/package.json b/examples/routify/api/vercel-ssr/package.json
new file mode 100644
index 0000000000..16aba092b0
--- /dev/null
+++ b/examples/routify/api/vercel-ssr/package.json
@@ -0,0 +1,8 @@
+{
+ "scripts": {
+ "vercel-build": "node ./build.js"
+ },
+ "devDependencies": {
+ "rollup": "^2.28.2"
+ }
+}
\ No newline at end of file
diff --git a/examples/routify/assets/404.svg b/examples/routify/assets/404.svg
new file mode 100644
index 0000000000..1df9552b99
--- /dev/null
+++ b/examples/routify/assets/404.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/routify/assets/__app.html b/examples/routify/assets/__app.html
new file mode 100644
index 0000000000..100314c9e8
--- /dev/null
+++ b/examples/routify/assets/__app.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ Svelte app
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/routify/assets/favicon.ico b/examples/routify/assets/favicon.ico
new file mode 100644
index 0000000000..1708f408eb
Binary files /dev/null and b/examples/routify/assets/favicon.ico differ
diff --git a/examples/routify/assets/favicon.png b/examples/routify/assets/favicon.png
new file mode 100644
index 0000000000..7e6f5eb5a2
Binary files /dev/null and b/examples/routify/assets/favicon.png differ
diff --git a/examples/routify/assets/global.css b/examples/routify/assets/global.css
new file mode 100644
index 0000000000..ec905f5ece
--- /dev/null
+++ b/examples/routify/assets/global.css
@@ -0,0 +1,66 @@
+html, body {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+body {
+ color: #333;
+ margin: 0;
+ padding: 8px;
+ box-sizing: border-box;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
+}
+
+a {
+ color: rgb(0,100,200);
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a:visited {
+ color: rgb(0,80,160);
+}
+
+label {
+ display: block;
+}
+
+input, button, select, textarea {
+ font-family: inherit;
+ font-size: inherit;
+ padding: 0.4em;
+ margin: 0 0 0.5em 0;
+ box-sizing: border-box;
+ border: 1px solid #ccc;
+ border-radius: 2px;
+}
+
+input:disabled {
+ color: #ccc;
+}
+
+input[type="range"] {
+ height: 0;
+}
+
+button {
+ color: #333;
+ background-color: #f4f4f4;
+ outline: none;
+}
+
+button:disabled {
+ color: #999;
+}
+
+button:not(:disabled):active {
+ background-color: #ddd;
+}
+
+button:focus {
+ border-color: #666;
+}
diff --git a/examples/routify/assets/images/touch-icons/logo-192.png b/examples/routify/assets/images/touch-icons/logo-192.png
new file mode 100644
index 0000000000..4b4cb63ad1
Binary files /dev/null and b/examples/routify/assets/images/touch-icons/logo-192.png differ
diff --git a/examples/routify/assets/images/touch-icons/logo-800.png b/examples/routify/assets/images/touch-icons/logo-800.png
new file mode 100644
index 0000000000..4247234208
Binary files /dev/null and b/examples/routify/assets/images/touch-icons/logo-800.png differ
diff --git a/examples/routify/assets/manifest.json b/examples/routify/assets/manifest.json
new file mode 100644
index 0000000000..483ba301ba
--- /dev/null
+++ b/examples/routify/assets/manifest.json
@@ -0,0 +1,21 @@
+{
+ "background_color": "#ffffff",
+ "theme_color": "#E938C2",
+ "name": "Routify app",
+ "short_name": "Routify app",
+ "start_url": "/",
+ "display": "standalone",
+ "icons": [
+ {
+ "src": "/images/touch-icons/logo-192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/images/touch-icons/logo-800.png",
+ "sizes": "800x800",
+ "type": "image/png",
+ "purpose": "maskable any"
+ }
+ ]
+}
diff --git a/examples/routify/static/robots.txt b/examples/routify/assets/robots.txt
similarity index 100%
rename from examples/routify/static/robots.txt
rename to examples/routify/assets/robots.txt
diff --git a/examples/routify/netlify.toml b/examples/routify/netlify.toml
new file mode 100644
index 0000000000..9ed12cd620
--- /dev/null
+++ b/examples/routify/netlify.toml
@@ -0,0 +1,23 @@
+
+[build]
+ publish = "dist"
+ functions = "api/netlify"
+ command = "npm run build && cd api/netlify && npm run build"
+
+# Dev doesn't work yet. Any takers?
+# [dev]
+ # command = "npm run dev:ssr"
+ # targetPort = 5000
+ # publish = "assets"
+ # autoLaunch = true
+
+[[redirects]]
+ # SSR and SPA
+ from = "/*"
+ to = "/.netlify/functions/ssr"
+ status = 200
+
+ # SPA only
+ # from = "/*"
+ # to = "/__app.html"
+ # status = 200
\ No newline at end of file
diff --git a/examples/routify/package.json b/examples/routify/package.json
index c40d439528..f1c125bd1e 100644
--- a/examples/routify/package.json
+++ b/examples/routify/package.json
@@ -1,40 +1,61 @@
{
- "version": "0.1.0",
- "private": true,
+ "name": "routify-carbon-app",
+ "version": "1.0.0",
+ "@comments scripts": {
+ "dev": "develop with blazing fast rebuilds",
+ "dev:features": "develop with features like SSR and serviceworker enabled",
+ "build": "run build scripts below",
+ "build:app": "build single page application (SPA)",
+ "build:static": "Generate static pages",
+ "serve": "serve content in 'dist' folder",
+ "rollup": "run the rollup bundler",
+ "nollup": "run the nollup no-bundler",
+ "routify": "run routify"
+ },
"scripts": {
- "dev": "run-p dev:*",
- "dev:rollup": "rollup -cw",
- "dev:routify": "routify",
- "build": "routify -b && rollup -c && routify export"
+ "dev": "run-p routify nollup",
+ "dev:ssr": "run-p routify rollup",
+ "build": "run-s build:*",
+ "build:app": "routify -b && rollup -c",
+ "build:static": "spank",
+ "serve": "spassr --ssr",
+ "rollup": "rollup -cw",
+ "nollup": "nollup -c",
+ "routify": "routify"
},
"devDependencies": {
- "@rollup/plugin-commonjs": "^13.0.0",
- "@rollup/plugin-node-resolve": "^8.1.0",
- "@rollup/plugin-replace": "^2.3.3",
- "@sveltech/routify": "^1.9.1",
- "carbon-components-svelte": "^0.12.0",
- "marked": "^1.1.1",
- "mdsvex": "^0.8.2",
- "node-sass": "^4.14.1",
+ "@rollup/plugin-commonjs": "^15.0.0",
+ "@rollup/plugin-node-resolve": "^10.0.0",
+ "@roxi/routify": "^2.8.5",
+ "carbon-components-svelte": "^0.27.0",
+ "carbon-icons-svelte": "^10.23.0",
+ "cross-env": "^7.0.2",
+ "fs-extra": "^9.0.1",
+ "nollup": "^0.13.13",
"npm-run-all": "^4.1.5",
- "remark-slug": "^6.0.0",
- "rollup": "^2.18.1",
- "rollup-plugin-copy": "^3.3.0",
+ "postcss": "^8.1.4",
+ "postcss-import": "^13.0.0",
+ "rollup": "^2.33.1",
+ "rollup-plugin-hot": "^0.1.1",
+ "rollup-plugin-inject-process-env": "^1.3.1",
"rollup-plugin-livereload": "^2.0.0",
- "rollup-plugin-postcss": "^3.1.8",
- "rollup-plugin-svelte": "^5.2.3",
- "rollup-plugin-svelte-hot": "^0.9.2",
+ "rollup-plugin-svelte": "^6.1.0",
+ "rollup-plugin-svelte-hot": "^0.11.1",
"rollup-plugin-terser": "^7.0.2",
- "routify-plugin-frontmatter": "^1.0.1",
- "spassr": "^1.1.2",
- "svelte": "^3.23.2"
+ "rollup-plugin-workbox": "^5.2.1",
+ "spank": "^1.5.1",
+ "spassr": "^2.2.0",
+ "svelte": "^3.29.4",
+ "svelte-preprocess": "^4.5.2",
+ "tossr": "^1.3.1"
},
"routify": {
- "extensions": "svelte,md",
- "routifyDir": ".routify",
- "dynamicImports": true,
- "plugins": {
- "routify-plugin-frontmatter": {}
- }
+ "extensions": "svelte,html,svx,md"
+ },
+ "spassr": {},
+ "spank": {
+ "blacklist": [
+ "/example/modal/basic/4"
+ ]
}
}
diff --git a/examples/routify/rollup.config.js b/examples/routify/rollup.config.js
index b11a80b725..5acd152378 100644
--- a/examples/routify/rollup.config.js
+++ b/examples/routify/rollup.config.js
@@ -1,24 +1,93 @@
-import { createRollupConfigs } from "./scripts/base.config.js";
-import slug from "remark-slug";
-import { mdsvex } from "mdsvex";
+import svelte from 'rollup-plugin-svelte-hot';
+import Hmr from 'rollup-plugin-hot'
+import resolve from '@rollup/plugin-node-resolve';
+import commonjs from '@rollup/plugin-commonjs';
+import livereload from 'rollup-plugin-livereload';
+import { terser } from 'rollup-plugin-terser';
+import { copySync, removeSync } from 'fs-extra'
+import { spassr } from 'spassr'
+import getConfig from '@roxi/routify/lib/utils/config'
+import autoPreprocess from 'svelte-preprocess'
+import postcssImport from 'postcss-import'
+import { injectManifest } from 'rollup-plugin-workbox'
+import injectProcessEnv from 'rollup-plugin-inject-process-env'
+
+const { distDir } = getConfig() // use Routify's distDir for SSOT
+const assetsDir = 'assets'
+const buildDir = `dist/build`
+const isNollup = !!process.env.NOLLUP
const production = !process.env.ROLLUP_WATCH;
-export const config = {
- staticDir: "static",
- distDir: "dist",
- buildDir: "dist/build",
- serve: !production,
- production,
- rollupWrapper: (cfg) => cfg,
- svelteWrapper: (svelte) => {
- svelte.preprocess = [mdsvex({ remarkPlugins: [slug], extension: "md" })];
- svelte.extensions = [".svelte", ".md"];
- return svelte;
- },
- swWrapper: (cfg) => cfg,
-};
-
-const configs = createRollupConfigs(config);
-
-export default configs;
+// clear previous builds
+removeSync(distDir)
+removeSync(buildDir)
+
+
+const serve = () => ({
+ writeBundle: async () => {
+ const options = {
+ assetsDir: [assetsDir, distDir],
+ entrypoint: `${assetsDir}/__app.html`,
+ script: `${buildDir}/main.js`
+ }
+ spassr({ ...options, port: 5000 })
+ spassr({ ...options, ssr: true, port: 5005, ssrOptions: { inlineDynamicImports: true, dev: true } })
+ }
+})
+const copyToDist = () => ({ writeBundle() { copySync(assetsDir, distDir) } })
+
+
+export default {
+ preserveEntrySignatures: false,
+ input: [`src/main.js`],
+ output: {
+ sourcemap: true,
+ format: 'esm',
+ dir: buildDir,
+ // for performance, disabling filename hashing in development
+ chunkFileNames:`[name]${production && '-[hash]' || ''}.js`
+ },
+ plugins: [
+ svelte({
+ dev: !production, // run-time checks
+ // Extract component CSS — better performance
+ css: css => css.write(`bundle.css`),
+ hot: isNollup,
+ preprocess: [
+ autoPreprocess({
+ postcss: { plugins: [postcssImport()] },
+ defaults: { style: 'postcss' }
+ })
+ ]
+ }),
+
+ // resolve matching modules from current working directory
+ resolve({
+ browser: true,
+ dedupe: importee => !!importee.match(/svelte(\/|$)/)
+ }),
+ commonjs(),
+
+ production && terser(),
+ !production && !isNollup && serve(),
+ !production && !isNollup && livereload(distDir), // refresh entire window when code is updated
+ !production && isNollup && Hmr({ inMemory: true, public: assetsDir, }), // refresh only updated code
+ injectProcessEnv({
+ NODE_ENV: production ? 'production': 'development'
+ }),
+ injectManifest({
+ globDirectory: assetsDir,
+ globPatterns: ['**/*.{js,css,svg}', '__app.html'],
+ swSrc: `src/sw.js`,
+ swDest: `${distDir}/serviceworker.js`,
+ maximumFileSizeToCacheInBytes: 10000000, // 10 MB,
+ mode: 'production'
+ }),
+ production && copyToDist(),
+ ],
+ watch: {
+ clearScreen: false,
+ buildDelay: 100,
+ }
+}
diff --git a/examples/routify/sandbox.config.json b/examples/routify/sandbox.config.json
new file mode 100644
index 0000000000..5d8e2b1eaf
--- /dev/null
+++ b/examples/routify/sandbox.config.json
@@ -0,0 +1,6 @@
+{
+ "container": {
+ "port": 5000,
+ "template": "node"
+ }
+}
diff --git a/examples/routify/scripts/base.config.js b/examples/routify/scripts/base.config.js
deleted file mode 100644
index de4fda8fb5..0000000000
--- a/examples/routify/scripts/base.config.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import svelte from "rollup-plugin-svelte-hot";
-import resolve from "@rollup/plugin-node-resolve";
-import commonjs from "@rollup/plugin-commonjs";
-import livereload from "rollup-plugin-livereload";
-import { terser } from "rollup-plugin-terser";
-import copy from "rollup-plugin-copy";
-import fs from "fs";
-import replace from "@rollup/plugin-replace";
-import postcss from "rollup-plugin-postcss";
-import { spassr } from "spassr";
-import { version } from "../package.json";
-
-export function createRollupConfigs(config) {
- const { production, serve, distDir } = config;
- const useDynamicImports = process.env.BUNDLING === "dynamic" || !!production;
-
- fs.rmdirSync(distDir, { recursive: true });
-
- if (serve) spassr({ serveSpa: true, serveSsr: true, silent: false });
-
- return [
- baseConfig(config, { dynamicImports: false }),
- useDynamicImports && baseConfig(config, { dynamicImports: true }),
- ].filter(Boolean);
-}
-
-function baseConfig(config, ctx) {
- const { dynamicImports } = ctx;
- const {
- staticDir,
- distDir,
- production,
- buildDir,
- svelteWrapper,
- rollupWrapper,
- } = config;
-
- const outputConfig = !!dynamicImports
- ? { format: "esm", dir: buildDir }
- : { format: "iife", file: `${buildDir}/bundle.js` };
-
- const svelteConfig = {
- dev: !production,
- css: (css) => css.write(`${buildDir}/bundle.css`, !production),
- hot: false,
- };
-
- const rollupConfig = {
- inlineDynamicImports: !dynamicImports,
- input: "src/main.js",
- output: { name: "routify_app", sourcemap: !production, ...outputConfig },
- plugins: [
- copy({
- targets: [
- { src: [`${staticDir}/*`, "!*/(__index.html)"], dest: distDir },
- {
- src: [`${staticDir}/__index.html`],
- dest: distDir,
- rename: "__app.html",
- transform,
- },
- ],
- copyOnce: true,
- flatten: false,
- }),
- replace({ "process.env.VERSION": JSON.stringify(version) }),
- postcss({
- extract: "bundle.css",
- extensions: [".css"],
- }),
- svelte(svelteWrapper(svelteConfig, ctx)),
- resolve({
- browser: true,
- dedupe: (importee) => !!importee.match(/svelte(\/|$)/),
- }),
- commonjs(),
- production && terser(),
- !production && livereload(distDir),
- ],
- watch: {
- clearScreen: false,
- buildDelay: 100,
- },
- };
-
- return rollupWrapper(rollupConfig, ctx);
-
- function transform(contents) {
- const scriptTag =
- typeof config.scriptTag != "undefined"
- ? config.scriptTag
- : '';
- const bundleTag = '';
- return contents
- .toString()
- .replace("__SCRIPT__", dynamicImports ? scriptTag : bundleTag);
- }
-}
diff --git a/examples/routify/src/App.svelte b/examples/routify/src/App.svelte
index e2d19ce3c6..1e38805542 100644
--- a/examples/routify/src/App.svelte
+++ b/examples/routify/src/App.svelte
@@ -1,6 +1,10 @@
-
+
+
+
\ No newline at end of file
diff --git a/examples/routify/src/Serviceworker.svelte b/examples/routify/src/Serviceworker.svelte
new file mode 100644
index 0000000000..1392d0a91a
--- /dev/null
+++ b/examples/routify/src/Serviceworker.svelte
@@ -0,0 +1,19 @@
+
diff --git a/examples/routify/src/main.js b/examples/routify/src/main.js
index 941f6c8ea1..bf553e25ca 100644
--- a/examples/routify/src/main.js
+++ b/examples/routify/src/main.js
@@ -1,7 +1,6 @@
-import "carbon-components-svelte/css/all.css";
-import HMR from "@sveltech/routify/hmr";
-import App from "./App.svelte";
+import HMR from '@roxi/routify/hmr'
+import App from './App.svelte';
-const app = HMR(App, { target: document.body }, "routify-app");
+const app = HMR(App, { target: document.body }, 'routify-carbon-app')
-export default app;
+export default app;
\ No newline at end of file
diff --git a/examples/routify/src/pages/_fallback.svelte b/examples/routify/src/pages/_fallback.svelte
index f2d685401f..631de87ea1 100644
--- a/examples/routify/src/pages/_fallback.svelte
+++ b/examples/routify/src/pages/_fallback.svelte
@@ -1,5 +1,5 @@
diff --git a/examples/routify/src/pages/_layout.svelte b/examples/routify/src/pages/_layout.svelte
index b3f8d0dc23..eb8af34152 100644
--- a/examples/routify/src/pages/_layout.svelte
+++ b/examples/routify/src/pages/_layout.svelte
@@ -1,5 +1,5 @@