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 to add transformEntryToHtml hook in plugins #8000

Open
4 tasks done
saurabhdaware opened this issue May 3, 2022 · 6 comments
Open
4 tasks done

Proposal to add transformEntryToHtml hook in plugins #8000

saurabhdaware opened this issue May 3, 2022 · 6 comments

Comments

@saurabhdaware
Copy link
Contributor

saurabhdaware commented May 3, 2022

Clear and concise description of the problem

Think of this directory structure-

|- nested /
|--|- about.ejs
|- index.ejs
|- main.js 
|- vite.config.js

Currently, seems like there is no clear way to do the <-- template --> to HTML conversion during SSG. transformIndexHtml only runs for files with .html extension and transform can only output JavaScript and not HTML.

In the above example, I am guessing the implementation would look something like this-

- Turn EJS to temporary HTML files
- Set those newly created HTML files in the `input` option while calling vite.build 
- Delete the temporary HTML files (Since they are not going to have all the styles and scripts included)

This is exactly how I am doing things in the SSG that I am working on-

https://github.com/abelljs/abell/blob/387cf15dc81471a4f1e722fc9ad28541c64de2f5/packages/abell/src/cli/generate.ts#L53-L73

  • I turn .abell -> temporary .html files (they don't have prod scripts and styles in them)
  • I run Vite's build by passing these new HTML files as input so that they will take care of injecting scripts and styles and generate dist
  • Then I delete the temporary HTML files

This seems to be missing for all template engines.

For example-

Suggested solution

A new hook called transformEntryToHtml.

Example-

// plugin code
export function ViteEjsPlugin(): Plugin {
  return {
    name: "vite-plugin-ejs",
    // Similar to `transformIndexHtml` except it runs for any entry file irrespective of the extension
    transformEntryToHtml(ejsCode: string): string {
      const html = ejs.render(ejsCode)
      return html   
    }
  };
}
// Plugin consumer's vite.config.ts
// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  build: {
    rollupOptions: {
      input: ['./index.ejs', './nested/about.ejs']
    }
  }
})

This will simplify the SSG flow a lot and will allow plugins like vite-plugin-ejs to have .ejs extension.

It will allow SSGs like Abell to build the output without generating temporary HTML files during the build.

Alternative

Alternative would be some way to call transformIndexHtml hook for files that are not HTML (don't have .html extension).

Additional context

Validations

@sapphi-red
Copy link
Member

related: #2321

@Pyrolistical
Copy link

ditto for https://github.com/vbenjs/vite-plugin-html, it uses ejs as well but templates MUST end with .html

@Pyrolistical
Copy link

Pyrolistical commented Jul 15, 2022

I think a simpler hook would be createIndexHtml. This would require less configuration and would allow us to write:

// vite.config.js

import {render} from 'ejs'
import {readFile, writeFile} from 'node:fs/promises'

// type createIndexHtml = {
//   dependencies: string[];
//   create: () => Promise<string>;
// }

const injectEjs = ({source, destination, data}) => {
  name: "inject-ejs",
  createIndexHtml: {
    dependencies: [source],
    async create() {
      const template = await readFile(source, 'utf8')
      const html = await render(template, data, {
        async: true
      })
      await writeFile(destination, html)
      return destination
    }
  }
};

export default () => {
  return {
    plugins: [
      injectEjs({
        source: 'index.html.ejs',
        destination: 'index.html',
        data: {
          title: 'some title'
        }
      })
    ]
  }
}

create returns a filename of a created html which is used like any other html entry point. createIndexHtml would need to be run before everything.

There is also a dependencies array which is all the source files the plugin will read. This would allow Vite to file watch the dependencies and only run the plugin when the contents have changed.

@lubomirblazekcz
Copy link
Contributor

This hook (or similar) would actually solve my hacky solution in vituum. Where I'm using a workaround with renaming the files to .html before build to add support for various template engine ext-names, similiar to @saurabhdaware solution.

@joshamaju
Copy link

Any updates on this? seems to be a common point a lot of people have arrived at

@lubomirblazekcz
Copy link
Contributor

Here is an updated vituum implementation which uses buildStart and buildEnd rollup hooks to rename files to .html for build and viteDevServer.middlewares for dev server support. If anyone wants you can use this workaround.

https://github.com/vituum/vituum/blob/3348010f053da61ee33c6bc5db120bd5a4b07e3b/src/utils/build.js#L31
https://github.com/vituum/vituum/blob/3348010f053da61ee33c6bc5db120bd5a4b07e3b/src/utils/common.js#L89

Here is a working example of vite plugin that supports .twig templates
https://github.com/vituum/vite-plugin-twig/blob/3b91629f7b4a7a8588a8c7c8dc2e4c5859c9f23f/index.js#L151

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

5 participants