├── .github └── workflows │ └── test-suite-ci.yml ├── .gitignore ├── README.md ├── configs ├── app_config.js ├── default.config.js └── svite.config.js ├── index.d.ts ├── package.json ├── postBuild.js ├── spassr.png ├── src ├── cli.js ├── config.js └── spassr.js ├── test ├── dynamic-import │ ├── dist │ │ ├── file.js │ │ ├── index.html │ │ └── main.js │ └── test.spec.js └── package.json └── tsconfig.json /.github/workflows/test-suite-ci.yml: -------------------------------------------------------------------------------- 1 | name: Test Suite CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | name: Test on NodeJS v${{ matrix.node-version }} on ${{ matrix.os }} 8 | runs-on: ${{ matrix.os }} 9 | 10 | strategy: 11 | matrix: 12 | node-version: [12.x, 14.x] 13 | os: [ubuntu-latest, windows-latest, macOS-latest] 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Use Node.js ${{ matrix.node-version }} 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node-version }} 21 | - run: npm i 22 | - run: npm test 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /dist/ 3 | .DS_Store 4 | **/.history 5 | **/__roxi-ssr-bundle.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | routify
3 |
4 | 5 | ### Small Express server with SSR 6 | 7 | #### Usage example 8 | 9 | $ npx spassr --assets-dir dist --entrypoint dist/index.html --script dist/build/bundle.js --ssr 10 | 11 | #### Configuration 12 | 13 | Spassr can be configured through `CLI`, `package.json`, `spassr.config.js` and `.env`. 14 | 15 | Environment variables are converted from snake_case to camelCase, so `SPASSR_assets_dir = dist` becomes `{... assetsDir: 'dist'}` 16 | 17 | For configuration options, refer to the API below. 18 | 19 | * * * 20 | 21 | ### API 22 | 23 | 24 | 25 | ##### Table of Contents 26 | 27 | - [spassr](#spassr) 28 | - [Parameters](#parameters) 29 | - [Config](#config) 30 | - [Properties](#properties) 31 | - [Eval](#eval) 32 | - [Parameters](#parameters-1) 33 | - [config](#config-1) 34 | 35 | #### spassr 36 | 37 | ##### Parameters 38 | 39 | - `options` **Partial<config.Config>** \* 40 | 41 | #### Config 42 | 43 | Type: [object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) 44 | 45 | ##### Properties 46 | 47 | - `assetsDir` **([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>)** folders with static content to be served. 48 | - `entrypoint` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** HTML template, eg. assets/index.html. 49 | - `script` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** path to app, eg. build/bundle.js. 50 | - `port` **([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number))** port to serve on. 51 | - `ssr` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** enable SSR for routes not resolved in assetsDir. 52 | - `silent` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** quiet console.log. 53 | - `middleware` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function)** function to customize SPA server (_Not available in CLI_). 54 | - `ssrOptions` **Partial<tossr.Config>** options to pass to ssr. 55 | 56 | 57 | #### Eval 58 | 59 | Called before/after the app script is evaluated 60 | 61 | Type: [Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function) 62 | 63 | ##### Parameters 64 | 65 | - `dom` **[object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** The DOM object 66 | 67 | #### config 68 | 69 | Type: [Config](#config) 70 | 71 | 72 | --- 73 | 74 | Business vector created by teravector - www.freepik.com 75 | -------------------------------------------------------------------------------- /configs/app_config.js: -------------------------------------------------------------------------------- 1 | const map = { 2 | template: 'entrypoint' 3 | } 4 | 5 | module.exports = { 6 | name: 'appConfig', 7 | condition: ({ pkgjson }) => pkgjson.appConfig, 8 | supersedes: ['default', 'svite'], 9 | config: ({ pkgjson }) => { 10 | const cfg = Object.entries(pkgjson.appConfig) 11 | .reduce((acc, [key, val]) => ({ 12 | ...acc, 13 | [map[key] || key]: val 14 | }), {}) 15 | 16 | cfg.assetsDir = [cfg.distDir, cfg.assetsDir].filter(Boolean) 17 | 18 | return cfg 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /configs/default.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'Default', 3 | condition: () => true, 4 | config: ({ pkgjson }) => { 5 | 6 | // set some healthy defaults 7 | const defaults = { 8 | "assets": "assets", 9 | "dist": "dist", 10 | "script": "dist/build/main.js", 11 | "template": "assets/__app.html" 12 | } 13 | 14 | // merge with the app field from package.json, if it exists 15 | const config = { ...defaults, ...pkgjson.options } 16 | 17 | return { 18 | // prioritize 'dist' over 'assets', in case asset has been transformed 19 | "assetsDir": [config.dist, config.assets], 20 | "script": config.script, 21 | "entrypoint": config.template, 22 | "ssrOptions": { 23 | "inlineDynamicImports": true 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /configs/svite.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'Svite', 3 | condition: ({ pkgjson }) => pkgjson.dependencies['@svitejs/vite-plugin-svelte'], 4 | supersedes: ['default'], 5 | config: () => { 6 | const config = { 7 | assetsDir: 'dist', 8 | entrypoint: 'dist/index.html', 9 | ssrOptions: { inlineDynamicImports: true } 10 | } 11 | 12 | const script = getScript(config.entrypoint) 13 | if (script) 14 | config.script = `dist${script}` 15 | 16 | return config 17 | } 18 | } 19 | 20 | function getScript(entrypoint) { 21 | const { readFileSync, existsSync } = require('fs') 22 | if (existsSync(entrypoint)) 23 | return readFileSync(entrypoint, 'utf8') 24 | .match(/\n
imported
\n \n\n` 25 | t.log('RES', res) 26 | t.is(res, expected) 27 | 28 | }) 29 | 30 | test('timeouts', async t => { 31 | const res2 = await fetch('http://127.0.0.1:5000/timeout').then(res => res.text()) 32 | t.log('RES2', res2) 33 | const expected2 =`\n
imported
\n \n\n` 34 | t.is(res2, expected2) 35 | }) 36 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "allowJs": true, 5 | "checkJs": true, 6 | "emitDeclarationOnly": true, 7 | "outFile": "index.d.ts" 8 | }, 9 | "include": ["src"] 10 | } 11 | --------------------------------------------------------------------------------