riot / ssr

Riot.js node Server Side Rendering
MIT License
32 stars 8 forks source link

In Riot.js v5.4.3, `<template>` are directly output as `<template>` in HTML. #23

Closed nibushibu closed 3 years ago

nibushibu commented 3 years ago

I have prepared a sample for this issue.

https://github.com/nibushibu/riot-ssr-template-tag-bug/tree/main

I use riot/ssr to compile .riot to .html, the template tag with the is attribute will be directly displayed as <template is='...'></template> in compiled .html.

html-base.riot

<html-base>

  <head>
    <meta charset="utf-8">
    <title>{ state.title }</title>
    <meta if="{ props.meta }" each="{ meta in props.meta }" {...meta}>
    <meta if="{ !props.meta }" each="{ meta in state.meta }" {...meta}>
    <meta name="viewport" content="width=device-width,initial-scale=1">
  </head>

  <body>
    <slot name="default"></slot>
  </body>

  <script>
    export default function HtmlBase() {
      return {
        state: {
          title: 'Title',
          meta: [
            {
              name: 'description',
              content: 'description',
            },
          ],
        },
      }
    }
  </script>

index.riot

<html lang="ja">
<template is="html-base" title="{ state.title }" meta="{ state.meta }">
  <h1>Riot SSR</h1>
</template>
<script>
  import HtmlBase from '../components/html-base.riot'
  export default {
    components: {
      HtmlBase,
    },
    state: {
      title: 'Page Title',
    }
  }
</script>
</html>

I have run the following node.js script using riot/ssr to compile the above .riot file into HTML. (By the way, I also use Riot as a tool to generate static HTML in this way, just like Pug or EJS. It's very comfortable! 😃)

const fs = require('fs')
const path = require('path')
const glob = require('glob')
const mkdirp = require('mkdirp')
const { render } = require('@riotjs/ssr')
const register = require('@riotjs/ssr/register')
const srcDirFromRoot = './src/html/pages'
const outputDir = 'dist/'

register()

glob(`${srcDirFromRoot}/**/*.riot`, (err, files) => {
  if (err) return err
  generateHtml(files)
})

const generateHtml = (files) => {
  files.forEach((file) => {
    const Root = require(`.${file}`).default
    const html = render('html', Root)
    const dir = path.join(
      outputDir,
      file.replace(srcDirFromRoot, '').replace(/riot$/, 'html')
    )

    mkdirp(path.parse(dir).dir).then(() => {
      fs.writeFile(dir, html, (err) => {
        if (err) throw err
      })
    })
  })
}

↓↓↓

compiled index.html from index.riot

<!doctype html>
<html lang="ja">
  <template is="html-base" title="Page Title">
    <head>
      <meta charset="utf-8" />
      <title>Title</title>
      <meta name="description" content="description" />
      <meta name="viewport" content="width=device-width,initial-scale=1" />
    </head>
    <body>
      <h1>Riot SSR</h1>
    </body>
  </template>
</html>

Expected index.html (It is desirable that <template> and </template> are not output.)

<!doctype html>
<html lang="ja">
    <head>
      <meta charset="utf-8" />
      <title>Title</title>
      <meta name="description" content="description" />
      <meta name="viewport" content="width=device-width,initial-scale=1" />
    </head>
    <body>
      <h1>Riot SSR</h1>
    </body>
</html>

I tried this combination of the template tag and is directive in a normal compilation without SSR, but the above result was only obtained when using riot/ssr.

This seems to be due to the following changes made in the latest version of Riot.js v5.4.3. https://github.com/riot/riot/commit/b2afbb883a3c79f0534edc670376de67b384c985#diff-8ab20e4abf785f767031d866e0bd9245d7093cf4067d707da24a00bd3e253bf8R278

As a test, I reverted isTemplate() in riot/util/check.js to the code from v5.3.2, and got the expected result.