GithubHelp home page GithubHelp logo

noahlh / celestite Goto Github PK

View Code? Open in Web Editor NEW
221.0 10.0 8.0 2.87 MB

Beautifully reactive, server-side rendered Svelte apps w/ a Crystal backend

License: MIT License

Crystal 65.24% JavaScript 21.02% HTML 2.33% Makefile 6.25% Dockerfile 4.37% Svelte 0.79%
crystal framework web ssr amber amber-framework universal isomorphic svelte sapper

celestite's Introduction

celestite

Crystal + Svelte = โšก

Celestite allows you to use the full power of Svelte reactive components in your Crystal web apps. It's a drop-in replacement for your view layer -- no more need for intermediate .ecr templates. With celestite, you write your backend server code in Crystal, your frontend client code in JavaScript & HTML, and everything works together seamlessly...and fast.

Introduction

Read the full introductory blog post here.

Requirements

  • Crystal 0.35.1+
  • Yarn 1.12+
  • Node 10+

The render server was built using node 10.15.3 (in particular it uses the WHATWG URL Standard, which was added in Node 7+.) It doesn't need to do this, strictly-speaking, and if there's a compelling reason to support earlier versions of Node I'm happy to make this change.)

Installation

THIS IS PREVIEW / EARLY ALPHA SOFTWARE

This is not much more than a proof-of-concept at the moment, but it does work! Standard warnings apply - it will likely break/crash in spectacular and ill-timed glory, so don't poke it, feed it past midnight, or use it for anything mission-critical (yet).

Celestite has been developed / tested with the Amber web framework, but designed to work standalone as well. There's also no reason it won't work with Lucky, Kemal, Athena, etc. (but no work integrating with those has been done yet.) The steps below assume you'll be working with Amber.

1. Add celestite to your application's shard.yml and run shards install

dependencies:
  celestite:
    github: noahlh/celestite
    version: ~> 0.1.3

2. Include the helper Celestite::Adapter::Amber in your application_controller.cr

This adds the celestite_render macro.

  # application_controller.cr

  require "jasper_helpers"

  class ApplicationController < Amber::Controller::Base
    include JasperHelpers
+   include Celestite::Adapter::Amber
  end

3. Add celestite_amber_init.cr to /config/initializers

An example is provided. You can name this file whatever you want, just so long as it gets called upon initialization.

4. Add an _error.svelte to your views directory

This is required for the time being because Sapper expects it. If it's missing, your app will still work, but there will be some weirdness with CSS rendering (trust me - this cost me an evening ;)

<script>
  export let status;
  export let error;
</script>

<h1>{status}</h1>
<p>{error.message}</p>

4. Add a static route for your build_dir to Amber's static pipeline

This is because of a slight hitch with how Svelte works behind the scenes (via Sapper), but essentially: the client needs to be able to access the relevant JS files in /client, yet Sapper needs complete control over that directory (it wipes it with each new build). So we simultaneously give it its own directory and also make it available via the root path.

 # routes.cr

 pipeline :static do
   plug Amber::Pipe::Error.new
   plug Amber::Pipe::Static.new("./public")
+  plug Amber::Pipe::Static.new("./public/celestite")
 end

And finally...

5. Add your .svelte files and start building!

A note on naming: make sure you follow Sapper's file naming rules. Hint: the root component should be named index.svelte (all lowercase).

Usage details

celestite_render(context : Celestite::Context = nil, path : String? = nil, template : String? = nil)

Performs the render. This is to be called where you'd normally call render in your controllers. It doesn't need any parameters by default (it automatically extracts the path of the method calling it based on your Amber routes), but you may use the following optional parameters:

  • context : Celestite::Context

    Celestite uses a Hash literal called Celestite::Context. Any variables you'd like available in your components go in here, using a Symbol key of the desired name.

    So if you want to access example_crystal_data in your vue component, assign the relevant value to my_context[:example_crystal_data]. See example below for details

    This is acheived using Sapper's session-seeding mechanism.

  • path : String?

    If you need to manually specify which path you're rending (i.e. you're not in Amber), you can pass in a string parameter. In Amber this will be assigned a default value equal to the current Amber route the controller method is handling.

  • template : String?

    (Not implemented yet) Which layout/template you'd like to render the component in. Will use a default template specified in the init file if none specified on render.

Example controller

# home_controller.cr

class HomeController < ApplicationController
  def index
    data = 1 + 1
    context = Celestite::Context{:data => data}
    celestite_render(context)
  end
end

Server vs client rendering (Node/JavaScript)

Your .svelte components will automatically be rendered server-side before being sent to the client. This is usually seamless, but you'll need to be aware of any code (or libraries) that rely on browser-specific APIs (such as document or window). This will throw an error when the components are rendered in the context of node (vs the browser).

To get around this, you can import Sapper's onMount() function. Any function wrapped in onMount() will be rendered in the (browser) client only.

You can read more about server-side rendering considerations here.

Project status

My goal/philosophy is to release early, release often, and get as much user feedback as early in the process as possible, so even though the perfectionist in me would like to spend another 6 years improving this, by then it'll be 2024 and who knows we might all be living underwater. No time like the present.

Roadmap

Short-term goals:

  • Release the embarrassing 0.1.0 version (originally supported Vue)
  • Fix reloading issues (not everything restarts properly)
  • Figure out Hot Module Reloading (HMR)
  • Add support for Svelte (released in 0.1.2)
  • Get usage --> expose bugs
  • Get example / demo project live
  • Switch over to SveltKit when it's live

Longer-term goals:

  • Performance & code cleanliness improvements
  • Remove need for a separate node process / http (evaluate JS in crystal?)

Contributions / critique wanted!

This has been a solo project of mine and I would love nothing more than to get feedback on the code / improvements / contributions. I've found by far the best way to learn and level-up development skills is to have others review code that you've wrestled with.

That is to say, don't hold back. Report things that are broken, help improve some of the code, or even just fix some typos. Everyone (at all skill levels) is welcome.

  1. Fork it (https://github.com/noahlh/celestite/fork)
  2. Create your feature/bugfix branch (git checkout -b omg-this-fixed-so-many-bugs)
  3. Make magic (and don't forget to write tests!)
  4. Commit your changes (git commit -am 'Made a fix!')
  5. Push to the branch (git push origin omg-this-fixed-so-many-bugs)
  6. Create a new Pull Request
  7. ::party::

Contributors

celestite's People

Contributors

dependabot[bot] avatar noahlh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

celestite's Issues

installation fails

I added

celestite:
    github: noahlh/celestite
    version: ~> 0.1.2

and I also tried

celestite:
   github: noahlh/celestite

the result is always

# shards update
...
Fetching https://github.com/noahlh/celestite.git
Failed git ls-tree -r --full-tree --name-only v0.1.1 -- shard.yml (). Maybe a commit, branch or file doesn't exist?

Is there a solution?

Add option for static render

Several have suggested this and it's a good idea: We should add an option to celestite_render() to allow for a static render in production, which is to say, avoid a r/t to the Node server.

This will be for certain pages whose content we can reliably expect to be static / pre-rendered. If there's no crystal variables being sent (eg no DB calls, etc.) and no server-side node requirements, then we can simply serve up the pre-rendered HTML.

Add "--src" option

The entire celestite/node project should be configurable within the calling app, including all dependencies (in package.json) and the webpack config file.

This is needed so additional packages can be added to the node project without burdening the core celestite project with additional project-specific dependencies.

Lucky support

I am looking to use this with Lucky. Has anyone used this with Lucky? Is there a checklist to work through to get this to work with Lucky?

Unhandled exception in spawn: Unable to get info for "public/dist/cvue.main.js"

On very first load (before there's a /build directory). Doesn't seem to cause an actual issue, but should be fixed nonetheless.

Unhandled exception in spawn: Unable to get info for "public/dist/cvue.main.js": No such file or directory (Errno)
  from /usr/local/Cellar/crystal/0.27.0/src/file.cr:122:37 in 'info'
  from /usr/local/Cellar/crystal/0.27.0/src/file.cr:121:3 in 'info'
  from lib/amber/src/amber/support/client_reload.cr:47:7 in 'get_timestamp'
  from lib/amber/src/amber/support/client_reload.cr:53:9 in 'scan_files'
  from lib/amber/src/amber/support/client_reload.cr:16:9 in 'run'
  from lib/amber/src/amber/support/client_reload.cr:11:7 in '->'
  from /usr/local/Cellar/crystal/0.27.0/src/fiber.cr:255:3 in 'run'
  from /usr/local/Cellar/crystal/0.27.0/src/fiber.cr:75:34 in '->'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.