Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Provide an HTML file to be server rendered #1108

Open
matthewp opened this issue Jul 20, 2018 · 3 comments
Open

Proposal: Provide an HTML file to be server rendered #1108

matthewp opened this issue Jul 20, 2018 · 3 comments

Comments

@matthewp
Copy link
Contributor

Currently we rely on done-autorender, a steal extension, to make server rendering and reattachment work. What if instead you could simply do:

done-serve -p 8080 development.html

development.html

<!doctype html>
<html lang="en">
<head>
  <title>donejs-app</title>
</head>
<body>
  <my-app></my-app>

  <script src="node_modules/steal/steal.js" main></script>
</body>
</html>

package.json

{
  "name": "my-app",
  "main": "main.js",
  "version": "1.0.0",
  ...
}

main.js

import { DefineMap, Component, route, RoutePushstate } from "can";

const RouteViewModel = DefineMap.extend({ ... });

Component.extend({
  tag: "my-app",
  view: `Hello world!`,
  ViewModel: {
    routeData: { Default: RouteViewModel },

    init() {
      route.urlData = new RoutePushstate();
      route.register("{page}", { page: "home" });
      route.data = this.routeData;
      route.start();
    }
  }
});

This is nice because you have more control over when stuff happens, don't rely on special done-autorender behavior.

We'd need to provide a mechanism to do the swapping behavior that done-autorender does for reattachment. With incremental rendering I believe that wouldn't be needed though.

@justinbmeyer
Copy link
Contributor

How would <title> work?

@matthewp
Copy link
Contributor Author

I'm not sure, what's the common way of doing this in CanJS apps outside of done-autorender? Back in the day I would do something like $('head').html(template(data)).

In other frameworks it's common to define components that project their DOM somewhere else.. this project is a react component that sets the <head> contents.

There's also the long-standing issue about letting a Component control a callbacks.attr instead of a tag.

can-bind would work as well.

@matthewp
Copy link
Contributor Author

matthewp commented Aug 15, 2018

I like the idea of using an attr, I think it's a bit cleaner this way:

<html>
  <head my-head></head>
  <body>
    <my-app></my-app>
  </body>
</html>

Then to use:

Component.extend({
  attr: 'my-head',
  view: `
    <title>My App</title>
     {{#eq(page, 'cart')}}
       <meta name="page" content="cart">
     {{/eq}}
  `
});

The problem here is passing data. How do you pass data into this component? It has to be part of its ViewModel most likely. You could use can-bind to mix two ViewModels together (the main component and this one's), but that would be pretty advanced.


So, with that being the case, I think it instead makes more sense if donejs/canjs provides a component whose children are rendered into the <head>. Example:

my-app.js

import "can-head";
import Component from "can-component";
import view from "./view.stache";

Component.extend({
  tag: "my-app",
  view
});

view.stache

<can-head>
  <title>{{page}} | My App</title>
  <meta charset="utf-8">
  {{#eq(page, 'cart')}}
    <meta name="page" content="cart">
  {{/eq}}
</can-head>

<p>Normal content goes here.</p>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants