markdalgleish / static-site-generator-webpack-plugin

Minimal, unopinionated static site generator powered by webpack
MIT License
1.61k stars 97 forks source link

Cannot read property 'listenBeforeLeavingRoute' of undefined #61

Open ZigaVukcevicDev opened 7 years ago

ZigaVukcevicDev commented 7 years ago

Hi,

thank you for the plugin. Although, I can not set it up, as

a) I am getting error in console ERROR in TypeError: Cannot read property 'listenBeforeLeavingRoute' of undefined

b) Secondly, what should I write to template.ejs file?

Please see my webpack.config.js content:

const
    path = require('path'),
    StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');

const scope = { window: {} };

const paths = [
    '/hello/',
    '/world/'
];

var config = {
    context: path.join(__dirname, 'src'),
    entry: [
        './main.js'
    ],
    output: {
        path: path.join(__dirname, 'www'),
        filename: 'bundle.js',
        /* IMPORTANT!
         * You must compile to UMD or CommonJS
         * so it can be required in a Node context: */
        libraryTarget: 'umd'
    },
    module: {
        loaders: [
            {
                test: /\.jsx?$/,
                loader: 'babel-loader',
                exclude: /node_modules/
            }
        ]
    },
    resolveLoader: {
        root: [
            path.join(__dirname, 'node_modules')
        ]
    },
    resolve: {
        root: [
            path.join(__dirname, 'node_modules')
        ]
    },
    plugins: [
        new StaticSiteGeneratorPlugin('main', paths, {
            // Properties here are merged into `locals`
            // passed to the exported render function
            greet: 'Hello'
        }, scope)
    ]
};

module.exports = config;

and my main.js file

'use strict';

import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOMServer from 'react-dom/server';
import { Router, RouterContext, match, browserHistory, createMemoryHistory } from 'react-router';

import routes from './config/routes';
import template from './config/template.ejs';

// Client render (optional):
if (typeof document !== 'undefined') {
    const mount = document.getElementById('mount');

    document.addEventListener('DOMContentLoaded', function() {
        ReactDOM.render(<Router history={browserHistory} routes={routes} />, mount)
    });
}

// Exported static site renderer:
export default (locals, callback) => {
    const history = createMemoryHistory();
    const location = history.createLocation(locals.path);

    match({ routes, location }, (error, redirectLocation, renderProps) => {
        callback(null, template({
            html: ReactDOMServer.renderToString(<RouterContext {...renderProps} />),
            assets: locals.assets
        }));
    });
};

and finally my package.json content

"dependencies": {
    "babel-core": "^6.9.1",
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-react": "^6.5.0",
    "express": "^4.13.4",
    "react": "^15.1.0",
    "react-dom": "^15.1.0",
    "react-router": "^2.8.0",
    "webpack": "^1.13.1",
    "webpack-dev-middleware": "^1.6.1"
},
"devDependencies": {
    "static-site-generator-webpack-plugin": "^3.0.0"
}

What am I doing wrong? I can provide more files, if necessary.

jurosh commented 7 years ago

a) I have same issue with listenBeforeLeavingRoute. No solution yet. // but in docs there is used old rc version 1.0.0 so maybe this is causing issues b) as I understand, it's possible to use without this template - it only helps to render basic html (without react). As I understand it's probably used with templates loader (ejs-loader) configured in webpack so you can define basic html structure in nice way (but probably using es6 string notation is nice alternative some ${variable} inside).

Edit: a) I had typo in routes declaration passed into match as first parameter - now this error is gone..

HHogg commented 7 years ago

If anyone makes there way here, the issue for me was because I was using a redirect so essentially there wasn't a route for the path given to StaticSiteGenerateWebpackPlugin, so needed to handle the redirectLocation when matching the route... something along the lines of

export default function(locals, callback) {
  const history = createMemoryHistory();
  const location = history.createLocation(locals.path); 

  function matchLocation(location) {
    match({ routes, location }, (error, redirectLocation, renderProps) => {
      if (redirectLocation) {
        return matchLocation(redirectLocation);
      }

      callback(null, template({ ... }));
    });
  }

  matchLocation(location);
})

Just an idea, but I wonder if the issue above is because the routes /hello/ or /world/ are slightly incorrect, because of trailing forward slash?