Giter VIP home page Giter VIP logo

parcel-plugin-prerender's Introduction

parcel-plugin-prerender

Known Vulnerabilities

About

Much like the prerender-spa-plugin for Webpack, this plugin is to bring prerendering capabilities to Parcel. It is meant to be a drop-in solution for any site or single-page-app.

Installation

npm install parcel-plugin-prerender -D

Usage

By default, this plugin will render the / path when building with parcel (i.e. parcel build or process.env.NODE_ENV == "production"). As this plugin uses cosmiconfig, in order to configure the plugin, pass the configuration options in a prerender key in your package.json, or a JSON or YAML .prerenderrc file, or export the config object in a prerender.config.js file.

Example

If you just want to render multiple routes, you can pass a plain array in any of the above ways:

// .prerenderrc
["/", "/about", "/login", "/deep/nested/route"]

Otherwise, you must pass it in a routes key, in order to configure the renderer, as follows.

Render configuration

You can configure the renderer (browser) options by using the following example config:

{
  "routes": ["/", "/about"],
  "rendererConfig": {
    "renderAfterDocumentEvent": "prerender-trigger"
  }
}

This is particularly useful if you'd like to pre-fetch some API data or async config and make that part of your pre-rendered HTML.

In the example above, the / and /about pages will only be rendered when the custom DOM event prerender-trigger is dispatched.

You can do so in your code like the following:

document.dispatchEvent(new Event('prerender-trigger'));

The custom configuration can also be useful for debugging. If the resulting html does not look like what you're expecting you could use the following configuration:

{
  "routes": ["/", "/about"],
  "rendererConfig": {
    "headless": false
  }
}

To make the pre-render browser visible and you would be available to debug.

To see all the options available see this documentation

What is Prerendering?

To quote prerender-spa-plugin:

Recently, SSR (Server Side Rendering) has taken the JavaScript front-end world by storm. The fact that you can now render your sites and apps on the server before sending them to your clients is an absolutely revolutionary idea (and totally not what everyone was doing before JS client-side apps got popular in the first place...)

However, the same criticisms that were valid for PHP, ASP, JSP, (and such) sites are valid for server-side rendering today. It's slow, breaks fairly easily, and is difficult to implement properly.

Thing is, despite what everyone might be telling you, you probably don't need SSR. You can get almost all the advantages of it (without the disadvantages) by using prerendering. Prerendering is basically firing up a headless browser, loading your app's routes, and saving the results to a static HTML file. You can then serve it with whatever static-file-serving solution you were using previously. It just works with HTML5 navigation and the likes. No need to change your code or add server-side rendering workarounds.

In the interest of transparency, there are some use-cases where prerendering might not be a great idea.

  • Tons of routes - If your site has hundreds or thousands of routes, prerendering will be really slow. Sure you only have to do it once per update, but it could take ages. Most people don't end up with thousands of static routes, but just in-case...
  • Dynamic Content - If your render routes that have content that's specific to the user viewing it or other dynamic sources, you should make sure you have placeholder components that can display until the dynamic content loads on the client-side. Otherwise it might be a tad weird.

Available Renderers

Currently only @prerenderer/renderer-puppeteer is supported, although @prerenderer/renderer-jsdom will probably be supported in the future

parcel-plugin-prerender's People

Contributors

abuffseagull avatar dependabot[bot] avatar lukechilds avatar sandman21dan avatar snyk-bot 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

Watchers

 avatar  avatar  avatar

parcel-plugin-prerender's Issues

Problem with parcels dynamic imports

If I use the dynamic import (see here)
with the prerenderer the resulting script tags use absolute paths starting with http://localhost:8000

something like

import('./main').then(function(page) {
  // Render page
  page.render()
})

results in

<script async type="text/javascript" charset="utf-8" src="http://localhost:8000/main.5c28f114.js"></script>

I didn't find a way to force relative paths in parcel. Any ideas how I could solve this elegantly?
(atm. i use something like .replace('http://localhost:8000/','./')

Relative deployment path support

When parcel is launched with the option parcel build --public-url ./ in order to build for deployment outside the root of the server, static-rendered routes no longer reference their resources correctly.

For my directory structure

  • build/
    • index.html
    • script_hash.js
    • myroute/
      • index.html

build/index.html will have a script tag that looks like:
<script src="script_hash.js"></script>
(Which is good)

BUT

build/myroute/index.html will also have a script tag which looks like:
<script src="script_hash.js"></script>
(Which will fail since the script is not in the same subdir)

The same applies to other resources (CSS, ico, etc.)

Better console output

Probably should add chalk back in and make it look better, like actual parcel, or the parcel-compress-plugin

Auto-generate routes

I often have some definitive way to get a list of routes from my app, like an import that defines my router/menu/content in react, for example. If there is interest, I'd be happy to make a PR to dynamically create routes.

It would be cool if I could tell parcel-plugin-prerender to import some file in parcel-space, then get a list of routes in a promise-returning (so I can do async calls) function. Here is an example that uses parcel-plugin-markdown-string to import a bunch of markdown files with front-matter:

package.json:

{
  "prerender": {
   "dynamicRoutes": "src/dynamicRoutes.js",
    "rendererConfig": {
      "renderAfterDocumentEvent": "prerender-trigger"
    }
  }
}

src/dynamicRoutes.js:

import fm from 'front-matter'
import rawArticles from '../articles/*.md'

export const routes = async (builder) => {
  return Object.keys(rawArticles).map(name => {
    const article = fm(rawArticles[name])
    return `/${article.attributes.slug || name}`
  })
}

Currently, I can work around this by running a script to generate .prerenderrc before I do the build, but it'd be cool if it was integrated.

Better testing

Currently the testing doesn't work half the time, so it needs to be reworked to work every time.

I think it has to do with parcel being run from the command line, but I think it didn't respect plugins if you used the API.
Other things to look into would be deleting the .cache before each run, and running the tests sequentially.

Fails when --public-url is set

If --public-url https://example.com is set so URLs use absolute paths (a requirement for og:image) then pre-rendering can't load any resources.

Or if the sites already published it will load the (old) live resources not the local resources.

TypeError: Cannot read property 'map' of undefined

I get this error:

TypeError: Cannot read property 'map' of undefined
    at PuppeteerRenderer.renderRoutes (/Users/konsumer/Desktop/parcel-ssr/node_modules/@prerenderer/renderer-puppeteer/es6/renderer.js:82:14)
    at Prerenderer.renderRoutes (/Users/konsumer/Desktop/parcel-ssr/node_modules/@prerenderer/prerenderer/es6/index.js:108:27)
    at Bundler.bundler.on (/Users/konsumer/Desktop/parcel-ssr/node_modules/parcel-plugin-prerender/index.js:24:48)
    at process._tickCallback (internal/process/next_tick.js:68:7)

with thisprerender.config.js:

module.exports = [
  '/',
  '/about',
  '/terms',
  '/features',
  '/stories',
  '/pricing'
]

I made this demo to illustrate the issue.

No paths are rendered by default

I'm not sure if this is a bug or the docs are incorrect.

From the docs:

By default, this plugin will render the / path. As this plugin uses cosmiconfig, in order to add more paths, add an array of strings corresponding to the paths you want rendered in a routes key in your package.json, or a JSON or YAML .prerenderrc file, or export the key in a prerender.config.js file.

This sounds like the routes config property is optional. However if I don't have "routes": ["/"] set I get an error:

TypeError: Cannot read property 'map' of undefined

It would be great if unset routes was inferred as "routes": ["/"] by default.

Minify HTML Output

parcel build normally minifies the HTML.

If you pre-render the site, the markup generated by JavaScript may be quite verbose.

It would be good to run the HTML through a minifier like html-minifier after pre-rendering before writing it back to disk.

Docs impovements

Prerender works only if NODE_ENV set to production. Please add to the readme, I spent some time trying to figure it out.

is the documentation about the configuration file wrong?

Docs says the configuration file should look like:

{
  "prerender": {
    "routes": ["/", "/about"],
    "rendererConfig": {
      "renderAfterDocumentEvent": "prerender-trigger"
    }
  }
}

but if I create a .prerenderrc like that it is not getting the routes array, instead it should look like:

{
    "routes": ["/", "/about"],
    "rendererConfig": {
      "renderAfterDocumentEvent": "prerender-trigger"
    }
}

I couldn't test if it works in the first way with a prerender.config.js it is giving me an error too.

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.