Skip to content

Commit

Permalink
compile server code from app folder
Browse files Browse the repository at this point in the history
  • Loading branch information
yysun committed Sep 26, 2024
1 parent d4b007c commit 75056b2
Show file tree
Hide file tree
Showing 13 changed files with 629 additions and 98 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ coverage
.cache
src/_lib
public
._build
demo/_
demo/api
137 changes: 91 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
## AppRun Site

[AppRun-Site](https://github.com/yysun/apprun-site) is a server plus command-line tool for building modern web applications with [AppRun](https://github.com/yysun/apprun). It has following features:
[AppRun-Site](https://github.com/yysun/apprun-site) is a server with [command-line tool](#command-line) for building modern web applications with [AppRun](https://github.com/yysun/apprun). It has following features:

* You can [create web pages](###quick-start) using AppRun components and markdown
* [Build](###build) your pages to dynamic modules and load them on demand
* [Run a server](###serve) as Single Page Applications (SPA) and Server-Side Rendering (SSR)
* Render your pages to create a [static website](###static-website)
* [File-based routing](##file-based-routing)
* [API endpoints](##api-endpoints)
* [Server-side actions](##server-side-actions)
* You can [create web pages](#quick-start) using AppRun components and markdown
* [Build](#build) your pages to dynamic modules and load them on demand
* Render your pages to create a [static website](#static-website)
* [Serve](#serve) Single Page Applications (SPA) and Server-Side Rendering (SSR)
* [File-based routing](#file-based-routing)
* [API endpoints](#api-endpoints)
* [Server-side actions](#server-side-actions)


## Quick Start
Expand All @@ -18,21 +18,17 @@ To create a new AppRun Site, run `npx apprun-site init`.
An AppRun-Site project has the following structure:

```
/_ <- action folder
/api <- api folder
/pages <- pages of the website
/index.html <- index page
/index.html <- index file
/index.tsx <- home page
/main.tsx <- start up code (registers web component and renders the layout)
/about
/index.tsx <- about page
/contact
/index.tsx <- contact page
/public <- static files (genegretd by the build command)
/server.js <- server code (genegretd by the build command for SSR)
```

The pages can tsx/jsx files (AppRun components).
The pages are tsx/jsx files (AppRun components).

```tsx
// pages/[page]/index.tsx -- functional component
Expand Down Expand Up @@ -68,61 +64,96 @@ This is a markdown file
The `npx apprun-site build` command compiles your code to the `public` folder. It generates the following files:

```
/public <- pages of the website
/pages <- pages of the website
/public <- static files (genegretd by the build command)
/index.html <- index page
/main.js <- start up code (registers web component and renders the layout)
/main.js <- start up code
/about
/index.js <- about page
/contact
/index.js <- contact page
/server.js <- server code (genegretd by the build command for SSR)
/server.js <- server code (genegretd for SPA and SSR)
```

### Static Website

The `npx apprun-site build --render` command renders your pages to create a static website in the `public` folder.

```
/public
/_.html <- /defualt page for SPA
/index.html <- rendered home page
/main.js
/index.js
/about
/index.html <- rendered about page
/index.js
/contact
/index.html <- rendered contact page
/index.js
/server.js <- server code (genegretd for SPA and SSR)
```

You can deploy the `public` folder to any static file server, such as GitHub Pages.

You can deploy the `public` folder to any static file server.


### Serve

Or you can run the server.js file to serve the pages with SSR.
You can run the generated `server.js` file to serve the pages.

```sh
node server.js
```

Modify the `server.js` file to fit your needs. The compiler will not overwrite the `server.js` file if it already exists.


### File-based Routing

When you run `npx apprun-site serve`, it starts a server that supports your code run as Single Page Applications (SPA) and supports Server-Side Rendering (SSR).
When you run `node serve.js`, it starts a server that supports your code run as Single Page Applications (SPA) and supports Server-Side Rendering (SSR).

On both the client side and the server side, it loads the pages on demand as dynamic modules using thw following steps:

* load the index.html
* load the main.js
* load the main.js (for the dynamic layout and the start up code)
* load the modules by path to render the pages:

```
/ <- /index.js
/about <- about/index.js
/contact <- contact/index.js
/public
/ <- /index.js
/about <- /about/index.js
/contact <- /contact/index.js
```

> Note:
> * The main.js should create a layout and a div with the id `main-app` to render the pages.
> * The page modules should create a div with the id `[page]-app` for sub pages. E.g., /docs/index.js should create a div with the id `docs-app` for its sub pages.
> * The page modules should create a div with the id `[page]-app` for sub pages. E.g., /docs/index.js should create a div with the id `docs-app` for its sub pages if any.
### Static Website

The `npx apprun-site build --render` command renders your pages to create a static website in the `public` folder.

### Server App

If you add server backend code, you can add an `app` folder with the following structure:

```
/index.html
/main.js
/index.js
/about
/index.html
/index.js
/contact
/index.html
/index.js
/app <- app folder (backend code)
/_ <- action folder
/api <- api folder
/pages <- pages of the website
```

The `build` command will compile the server code to allow the API endpoints and server-side actions.

If you only want to build the server code, you can use the `--server-only` option:

```sh
npx apprun-site build --server-only
```

### API Endpoints

The `build` command also generates a server.js file that can be used to serve API endpoints. You can add your API endpoints in the `api` folder.
The `build` command generated `server.js` can serve API endpoints. You can add your API endpoints in the `api` folder.

The API endpoints are served at the path `/api/[endpoint]`. For example, the `api/hello.js` file will be served at `/api/hello`.

Expand All @@ -137,6 +168,8 @@ export default (req, res) => {

You can add server-side actions in the `_` folder. The server-side actions are served at the path `/_/[action]`. For example, the `_/comic.js` file will be served at `/_/comic`.

Use the `//#if server`, `//#else`, and `//#endif` comments to separate the server-side code from the client-side code. The compiler will strip out the server-side code from the client-side code and vice versa.

```js
// _/comic.js
import action from 'apprun-site/action.js';
Expand All @@ -151,11 +184,9 @@ export default async (data) => {
}
```
The compiler will strip out the server-side code from the client-side code, noted by `//#if server` and `//#else`. So, no server side code will be visible on the client side.
The `action` function will POST to the `comic` action on the client side.
The `action` function will use fetch to POST to the `comic` action on the client side.

You can refer to the server-side action in your AppRun components:
You can refer to the server-side action in the client-side code:
```tsx
// components/comic.tsx
Expand All @@ -167,15 +198,29 @@ export default class Comic extends Component {
}
```
The benefit of referring to the server-side code is that you can get type checking, code completion and go-to-definition in your IDE.
The benefit of referring to the server-side code is that you can get type checking, code completion and goto-definition in your IDE.
## Command Line
You can use:
You can add a few npm scripts to your `package.json` file:
```json
{
"scripts": {
"start": "node server.js",
"dev": "apprun-site dev",
"build": "apprun-site build --clean",
"render": "apprun-site build --render",
"build:server": "apprun-site build --server-only",
"build:client": "apprun-site build --client-only"
}
}
```
Then you can run the following commands:
* _npm init_ to create a new AppRun Site
* _npm start_ to start the preview server
* _npm run dev_ to start the dev server
* _npm start_ to start the server
* _npm run dev_ to start the development
* _npm run build_ to build for production
* _npm run render_ to build a static website
Expand Down
17 changes: 14 additions & 3 deletions apprun-site-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { build } from './index.js';
import dev_server from './dev-server.js';
import app from './server.js';
import { routes } from './src/build-ts.js';
import build_server from './src/build-server.js';

async function init_options(source, options) {
source = (source && source !== '.') ? `${process.cwd()}/${source}` : `${process.cwd()}`;
Expand Down Expand Up @@ -122,12 +123,22 @@ program
.option('-w, --watch', 'watch the directory', false)
.option('-o, --output [output]', 'output directory', 'public')
.option('-p, --pages [pages]', 'pages directory', 'pages')
.option('--no-csr', 'no client side routing')
.option('-s --server-only', 'build server app', false)
.option('-b --client-only', 'build server app', false)
.option('-r --render', 'pre-render pages', false)
.option('--no-csr', 'no client side routing')
.action(async (source, options) => {
({ source, options } = await init_options(source, options));
options.dev = false;
await build(options);

if (!options['serverOnly']) {
options.dev = false;
await build(options);
}

if (!options['clientOnly']) {
await build_server(options);
}

if (options.render) {
options.ssr = true;
options.save = true;
Expand Down
11 changes: 0 additions & 11 deletions demo/_/comic.js

This file was deleted.

8 changes: 0 additions & 8 deletions demo/api/comic.js

This file was deleted.

9 changes: 9 additions & 0 deletions demo/app/api/comic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default async (req, res) => {
// let response = await fetch('https://xkcd.com/info.0.json');
// const current = await response.json();
// const num = Math.floor(Math.random() * current.num) + 1;
const num = Math.floor(Math.random() * 2990) + 1;
const response = await fetch(`https://xkcd.com/${num}/info.0.json`);
const comic = await response.json();
res.json(comic);
}
File renamed without changes.
7 changes: 6 additions & 1 deletion demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node --watch --watch-path public server.js"
"start": "node server.js",
"dev": "apprun-site dev",
"build": "apprun-site build --clean",
"render": "apprun-site build --render",
"build:server": "apprun-site build --server-only",
"build:client": "apprun-site build --client-only"
},
"keywords": [],
"author": "",
Expand Down
Loading

0 comments on commit 75056b2

Please sign in to comment.