Coder Social home page Coder Social logo

reuters-graphics / html-webpack-prerender-plugin Goto Github PK

View Code? Open in Web Editor NEW
14.0 4.0 5.0 1.29 MB

A plugin to prerender and inject JavaScript apps into the static markup generated by html-webpack-plugin at build time.

License: MIT License

JavaScript 98.63% HTML 1.37%

html-webpack-prerender-plugin's Introduction

html-webpack-prerender-plugin

A plugin to prerender and inject JavaScript apps into the static markup generated by html-webpack-plugin at build time.

npm version Reuters open source software

Why this?

At Reuters Graphics we are all about JAM stack. Avoiding the overhead of server maintenance keeps us lean, minimizes our technical debt and protects our ability to scale with our audience. But being serverless sometimes makes it more complex to use the tools we like to their best effect.

For example, we like to use modern frameworks like React, but rendering our content only in the client makes our pages slower for our readers and less SEO friendly.

This plugin lets us reap the benefits of server-side rendering in those frameworks but in the context of a static page. With it, we can pre-render our content at build time and, in the client, still hydrate a dynamic app.

Prior art

This app is heavily inspired by static-site-generator-webpack-plugin, which was itself an important foundation for Gatsby.js.

Quickstart

  1. Install
$ yarn add -D html-webpack-prerender-plugin html-webpack-plugin@next
  1. Configure webpack.
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPrerenderPlugin = require('html-webpack-prerender-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    path: './dist',
    filename: '[name].js',
    // This is important, because your app must
    // be executable in both a node AND browser
    // environment.
    libraryTarget: 'umd',
  },
  // ...
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/templates/index.html',
    }),
    new HtmlWebpackPrerenderPlugin({ main: '#root' }),
  ],
};
  1. Create a template with a root container for your app.
<!-- src/templates/index.html -->
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head></head>
  <body>
    <div id='root'></div>
  </body>
</html>
  1. Make sure your app exports a default function that renders a string of markup.
// src/js/index.js
export default = () => '<p>Hello world!</p>';

Rendered

<!-- src/templates/index.html -->
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head></head>
  <body>
    <div id="root"><p>Hello world!</p></div>
    <script src="main.js"></script>
  </body>
</html>

Next

Read the complete guide to the plugin configuration options.

Check out some example configurations:

Testing

$ yarn build && yarn test

html-webpack-prerender-plugin's People

Contributors

hobbes7878 avatar runemadsen avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar

html-webpack-prerender-plugin's Issues

Allow async?

Seems hacky but could check if return of default func is instanceof Promise or just require all signatures to be async...

app.default is not a function

I'm facing this error, I have the same webpack config as in your readme file.

 Error: HtmlWebpackPrerenderPlugin ERROR: Error rendering component.
  TypeError: app.default is not a function

My index.js

import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOMServer from 'react-dom/server';
import MyComponent from '../../pages/index';

const App = () => <h1>Hello world!</h1>;

if (document.body) {
  const div = document.getElementById('root');
  if (div.hasChildNodes()) {
    ReactDOM.hydrate(<MyComponent />, div);
  } else {
    ReactDOM.render(<MyComponent />, div);
  }
}

export default () => ReactDOMServer.renderToString(<App />);

Does not work with latest `html-webpack-plugin`

It seems that html-webpack-plugin changed its internal data structure when going out of beta, especially from data.plugin.childCompilationOutputName to data.outputName. I cloned down the repo and 7 tests are failing for version 4.3.0.

I am sending a pull request to fix this.

Error when building - self is not defined

Hi, I am trying to prerender a simple React project. In fact I duplicated the example found in docs/read.md in an exisitng project and adjusted my webpack.config.js to point to the correct app.js file (different filename).

I am getting this;
ERROR in Error: HtmlWebpackPrerenderPlugin ERROR: Error evaluating your app script.
ReferenceError: self is not defined

  • index.js:344 HtmlWebpackPrerenderPlugin.injectApp
    [corpoWeb]/[html-webpack-prerender-plugin]/dist/index.js:344:13

  • index.js:401
    [corpoWeb]/[html-webpack-prerender-plugin]/dist/index.js:401:43

  • index.js:128 _catch
    [corpoWeb]/[html-webpack-prerender-plugin]/dist/index.js:128:16

  • index.js:400
    [corpoWeb]/[html-webpack-prerender-plugin]/dist/index.js:400:24

  • index.js:118
    [corpoWeb]/[html-webpack-prerender-plugin]/dist/index.js:118:43

  • index.js:88 _cycle
    [corpoWeb]/[html-webpack-prerender-plugin]/dist/index.js:88:14

  • index.js:107 _forTo
    [corpoWeb]/[html-webpack-prerender-plugin]/dist/index.js:107:2

  • index.js:118 _forIn
    [corpoWeb]/[html-webpack-prerender-plugin]/dist/index.js:118:9

  • index.js:397
    [corpoWeb]/[html-webpack-prerender-plugin]/dist/index.js:397:22

My hunch is that it is a version compatibility issue but I am really not sure. In any case here are the different version of all modules I have ibn the sandbox:
"devDependencies": {
"@babel/core": "^7.14.6",
"@babel/preset-env": "^7.14.5",
"@babel/preset-react": "^7.14.5",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"css-loader": "^5.2.6",
"file-loader": "^6.2.0",
"html-loader": "^2.1.2",
"html-react-parser": "^1.3.0",
"html-webpack-plugin": "^5.3.1",
"html-webpack-prerender-plugin": "^0.1.0",
"markdown-loader": "^6.0.0",
"node-sass": "^6.0.0",
"react-hot-loader": "^4.13.0",
"sass-loader": "^12.1.0",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1",
"webpack": "^5.39.1",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0",
"styled-components": "^5.3.0"
}

Any feedback?

Feedback

First of all, thanks for creating this plugin. After trying my luck with static-site-generator-webpack-plugin and needing two different templates for SSR and client, this package solved all my problems. I just wanted to give a little feedback with my first impressions. I'm happy to submit some of these things as a PR if needed:

Needs html-webpack-plugin version 4.0

I spent half an hour try to get the plugin to work only to realize that it needs html-webpack-plugin version 4.0 to work. It would be great to state that in the README.

How to know it's a SSR render

When I got the rendering working, some code using the global navigator object broke, and I wanted to only run that code on the client side. In the docs, it looks like doing if(document.body) will do that, but the document body is also present via JSDOM during the Node render. I ended up adding a boolean to my scope:

new HtmlWebpackPrerenderPlugin({
  'index.html': {
    app: {
      selector: '#root',
        scope: {
          isSSRRender: true,
        }
     }
  }
})

And then doing this in a utils file:

export const isSSR = typeof isSSRRender !== 'undefined';

I can then use that variable to check whether it's running in Node or the client. This might be helpful for other people too.

new Plugin()

Some of the documentation README's has new Plugin(), which is confusing. This should probably be replaced with new HtmlWebpackPrerenderPlugin().

Hot module loader

This package, like static-site-generator-webpack-plugin does not work with the webpack dev server and hot module loading. It would be great to have a note that the plugin should only be added when running a production build.

That's all. Thanks!

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.