├── .gitmodules ├── quickjs ├── test262o_errors.txt ├── VERSION ├── examples │ ├── hello.js │ ├── hello_module.js │ ├── test_fib.js │ ├── fib_module.js │ ├── test_point.js │ ├── pi_bigfloat.js │ ├── pi_bigdecimal.js │ ├── fib.c │ ├── pi_bigint.js │ └── point.c ├── readme.txt ├── unicode_download.sh ├── tests │ ├── test_worker_module.js │ ├── test_worker.js │ ├── test262.patch │ ├── bjson.c │ ├── test_closure.js │ ├── test_op_overloading.js │ ├── test_bjson.js │ ├── test_qjscalc.js │ ├── test_std.js │ ├── test_loop.js │ ├── test_bignum.js │ └── test_language.js ├── LICENSE ├── libregexp-opcode.h ├── quickjs-libc.h ├── TODO ├── libregexp.h ├── list.h ├── release.sh ├── libunicode.h ├── Changelog ├── test262.conf ├── test262_errors.txt ├── unicode_gen_def.h ├── cutils.h ├── quickjs-atom.h └── Makefile ├── .gitignore ├── client.js ├── .editorconfig ├── server.js ├── index.html ├── Makefile ├── README.md ├── CMakeLists.txt ├── app.js ├── style.css ├── htm.js ├── CMakeLists.quickjs.txt ├── preact-render-to-string.js ├── tiny.c ├── htm.c └── preact.js /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quickjs/test262o_errors.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | build 3 | -------------------------------------------------------------------------------- /quickjs/VERSION: -------------------------------------------------------------------------------- 1 | 2021-03-27 2 | -------------------------------------------------------------------------------- /quickjs/examples/hello.js: -------------------------------------------------------------------------------- 1 | console.log("Hello World"); 2 | -------------------------------------------------------------------------------- /quickjs/readme.txt: -------------------------------------------------------------------------------- 1 | The main documentation is in doc/quickjs.pdf or doc/quickjs.html. 2 | -------------------------------------------------------------------------------- /quickjs/examples/hello_module.js: -------------------------------------------------------------------------------- 1 | /* example of JS module */ 2 | 3 | import { fib } from "./fib_module.js"; 4 | 5 | console.log("Hello World"); 6 | console.log("fib(10)=", fib(10)); 7 | -------------------------------------------------------------------------------- /quickjs/examples/test_fib.js: -------------------------------------------------------------------------------- 1 | /* example of JS module importing a C module */ 2 | 3 | import { fib } from "./fib.so"; 4 | 5 | console.log("Hello World"); 6 | console.log("fib(10)=", fib(10)); 7 | -------------------------------------------------------------------------------- /client.js: -------------------------------------------------------------------------------- 1 | import App from "./app.js" 2 | import {h, hydrate} from "./preact.js" 3 | import htm from './htm.js' 4 | 5 | const html = htm.bind(h); 6 | hydrate(html`<${App} page="All" />`, document.body); -------------------------------------------------------------------------------- /quickjs/examples/fib_module.js: -------------------------------------------------------------------------------- 1 | /* fib module */ 2 | export function fib(n) 3 | { 4 | if (n <= 0) 5 | return 0; 6 | else if (n == 1) 7 | return 1; 8 | else 9 | return fib(n - 1) + fib(n - 2); 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | import * as std from 'std' 2 | import App from 'app.js' 3 | import {h} from 'preact.js' 4 | import htm from 'htm.js' 5 | import preactRenderToString from 'preact-render-to-string.js' 6 | 7 | const html = htm.bind(h); 8 | 9 | std.out.puts(preactRenderToString(html`<${App} page="All" />`)) -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Preact 7 | 8 | 9 | PLACE_HOLDER 10 | 11 | 12 | -------------------------------------------------------------------------------- /quickjs/unicode_download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | url="ftp://ftp.unicode.org/Public/13.0.0/ucd" 5 | emoji_url="${url}/emoji/emoji-data.txt" 6 | 7 | files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \ 8 | SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \ 9 | UnicodeData.txt DerivedCoreProperties.txt NormalizationTest.txt Scripts.txt \ 10 | PropertyValueAliases.txt" 11 | 12 | mkdir -p unicode 13 | 14 | #for f in $files; do 15 | # g="${url}/${f}" 16 | # wget $g -O unicode/$f 17 | #done 18 | 19 | wget $emoji_url -O unicode/emoji-data.txt 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD_DIR=build 2 | BUILDTYPE?=MinSizeRel 3 | 4 | all: build 5 | 6 | build: 7 | @mkdir -p $(BUILD_DIR) 8 | cd $(BUILD_DIR); cmake ../ -DCMAKE_BUILD_TYPE=$(BUILDTYPE) 9 | $(MAKE) -C $(BUILD_DIR) -j4 10 | 11 | install: 12 | @$(MAKE) -C $(BUILD_DIR) install 13 | 14 | clean: 15 | @$(MAKE) -C $(BUILD_DIR) clean 16 | 17 | distclean: 18 | @rm -rf $(BUILD_DIR) 19 | 20 | build/qjsc: 21 | $(MAKE) -C $(BUILD_DIR) qjsc -j4 22 | 23 | gen: build/qjsc 24 | $(BUILD_DIR)/qjsc -c -m -o preact.c -N preact preact.js 25 | $(BUILD_DIR)/qjsc -c -m -o htm.c -N htm htm.js 26 | 27 | .PHONY: all build install clean distclean gen -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Quick-Preact-SSR 2 | Inspired By https://github.com/saghul/njk. Fast Preact SSR. 3 | 4 | ### Features 5 | - low overhead and very small (use quickjs) 6 | - pre-compile dependencies(include preact and htm, and also other components if we want) to bytecode, fast in ssr 7 | - share code with client, no redundancy 8 | 9 | ### Get Started 10 | ```bash 11 | make 12 | # qpreact 13 | ./build/qpreact-linux-x86_64 5000 server.js 14 | ``` 15 | Then, visit http://127.0.0.1:5000/, you can find the preact todo mvc in ssr. 16 | 17 | ## Others 18 | I change `quickjs` a little bit. So it's in here rather than submodule. 19 | -------------------------------------------------------------------------------- /quickjs/tests/test_worker_module.js: -------------------------------------------------------------------------------- 1 | /* Worker code for test_worker.js */ 2 | import * as std from "std"; 3 | import * as os from "os"; 4 | 5 | var parent = os.Worker.parent; 6 | 7 | function handle_msg(e) { 8 | var ev = e.data; 9 | // print("child_recv", JSON.stringify(ev)); 10 | switch(ev.type) { 11 | case "abort": 12 | parent.postMessage({ type: "done" }); 13 | break; 14 | case "sab": 15 | /* modify the SharedArrayBuffer */ 16 | ev.buf[2] = 10; 17 | parent.postMessage({ type: "sab_done", buf: ev.buf }); 18 | break; 19 | } 20 | } 21 | 22 | function worker_main() { 23 | var i; 24 | 25 | parent.onmessage = handle_msg; 26 | for(i = 0; i < 10; i++) { 27 | parent.postMessage({ type: "num", num: i }); 28 | } 29 | } 30 | 31 | worker_main(); 32 | -------------------------------------------------------------------------------- /quickjs/examples/test_point.js: -------------------------------------------------------------------------------- 1 | /* example of JS module importing a C module */ 2 | import { Point } from "./point.so"; 3 | 4 | function assert(b, str) 5 | { 6 | if (b) { 7 | return; 8 | } else { 9 | throw Error("assertion failed: " + str); 10 | } 11 | } 12 | 13 | class ColorPoint extends Point { 14 | constructor(x, y, color) { 15 | super(x, y); 16 | this.color = color; 17 | } 18 | get_color() { 19 | return this.color; 20 | } 21 | }; 22 | 23 | function main() 24 | { 25 | var pt, pt2; 26 | 27 | pt = new Point(2, 3); 28 | assert(pt.x === 2); 29 | assert(pt.y === 3); 30 | pt.x = 4; 31 | assert(pt.x === 4); 32 | assert(pt.norm() == 5); 33 | 34 | pt2 = new ColorPoint(2, 3, 0xffffff); 35 | assert(pt2.x === 2); 36 | assert(pt2.color === 0xffffff); 37 | assert(pt2.get_color() === 0xffffff); 38 | } 39 | 40 | main(); 41 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | 3 | project(qpreact LANGUAGES C) 4 | 5 | include(GNUInstallDirs) 6 | 7 | if (NOT CMAKE_BUILD_TYPE) 8 | message(STATUS "No build type selected, default to Release") 9 | set(CMAKE_BUILD_TYPE "Release") 10 | endif() 11 | message(STATUS "Building in ${CMAKE_BUILD_TYPE} mode") 12 | message(STATUS "Building with ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} on ${CMAKE_SYSTEM}") 13 | 14 | include(${CMAKE_SOURCE_DIR}/CMakeLists.quickjs.txt) 15 | 16 | add_executable(qpreact 17 | quickjs/quickjs-libc.c 18 | tiny.c 19 | preact.c 20 | htm.c 21 | ) 22 | 23 | set_target_properties(qpreact PROPERTIES 24 | C_STANDARD 11 25 | C_STANDARD_REQUIRED ON 26 | OUTPUT_NAME qpreact-$-$ 27 | ) 28 | 29 | target_compile_definitions(qpreact PRIVATE 30 | _GNU_SOURCE 31 | ) 32 | 33 | target_link_libraries(qpreact qjs m pthread dl) 34 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | import htm from './htm.js' 2 | import * as preact from './preact.js' 3 | 4 | const {Component, h, hydrate} = preact 5 | // Create your app 6 | const html = htm.bind(preact.h); 7 | 8 | class App extends Component { 9 | addTodo() { 10 | const { todos = [] } = this.state; 11 | this.setState({ todos: todos.concat(`Item ${todos.length}`) }); 12 | } 13 | render({ page }, { todos = [] }) { 14 | return html` 15 |
16 | <${Header} name="ToDo's (${page})" /> 17 |
    18 | ${todos.map(todo => html` 19 |
  • ${todo}
  • 20 | `)} 21 |
22 | 23 | <${Footer}>footer content here 24 |
25 | `; 26 | } 27 | } 28 | 29 | const Header = ({ name }) => html`

${name} List

` 30 | 31 | const Footer = props => html`