markdalgleish / static-site-generator-webpack-plugin

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

Webpack 2 compatibility : ERROR in ReferenceError: self is not defined #79

Open dbrrt opened 7 years ago

dbrrt commented 7 years ago

I can't having it working with Webpack 2, because it runs on server and returns :

ERROR in ReferenceError: self is not defined

Does one have been able solving it? Would it be possible to run it on client only ?

bpevs commented 7 years ago

I noticed this error as well. I'm currently working on two personal projects; it works in one, and in the other, I get the same error as you. The only difference in the surrounding code is mostly that one of them extracts the css and the other does not (sorry it's not the cleanest code, these are little in-progress personal projects).

This repo is working with 3.1, but and webpack 2 (I checked and it also works with 3.3, however): https://github.com/ivebencrazy/React-Starter/tree/basic-web

This one is broke with 3.3 and webpack 2: https://github.com/Blanket-Warriors/Zuck.js/tree/postcss-refactor

Currently not sure whether it's the plugin, or just misuse. I'll be looking into it a bit more the next day or two as I get the time. But I figured maybe linking them could help solve your problem in itself.

ERROR in ReferenceError: self is not defined
    at evalmachine.<anonymous>:4005:30
    at evalmachine.<anonymous>:4000:47
    at module.exports (evalmachine.<anonymous>:4022:68)
    at Object.<anonymous> (evalmachine.<anonymous>:64292:37)
    at __webpack_require__ (evalmachine.<anonymous>:30:30)
    at Object.defineProperty.value (evalmachine.<anonymous>:31917:15)
    at __webpack_require__ (evalmachine.<anonymous>:30:30)
    at Object.hasOwnProperty (evalmachine.<anonymous>:6452:15)
    at __webpack_require__ (evalmachine.<anonymous>:30:30)
    at Object.defineProperty.value (evalmachine.<anonymous>:31773:13)

edit: btw keep note of the deps while you're looking around. Since I started using Webpack 2 a bit early and I haven't updated everything, some of the dependencies are non-standard versions.

dbrrt commented 7 years ago

Thanks for having shared that code, it'll certainly help me. I also thought I might misused the plugin but it failed on other projects too.

alexleventer commented 7 years ago

Having the same issue w/ webpack 2.2.0-rc.3

bpevs commented 7 years ago

Hey, update; After looking around a tad, it looks like for me, this error is coming from isomorphic-fetch dependency (https://github.com/matthew-andrews/iso…). Seems similar to document is not defined kind of issues people get, since this pre rendering doesn't happen in a browser context. I don't have any more time to look at it today for why that's the case or for solutions, but that's my hunch. Check your polyfills and dependencies.

vectorsize commented 7 years ago

In my case this happened when with running StaticSiteGeneratorPlugin with webpack-de-server.

adding this conditional in the config fixed it:

if (!development) {
  config.plugins = config.plugins.concat([
    new StaticSiteGeneratorPlugin('bundle.js', routes)
  ])
}
jota commented 7 years ago

In case it helps someone, for me it was caused by "style-loader". Before i had it configured like so: loaders: ["style-loader", "css-loader", "postcss-loader"]

and solved it by using the ExtractTextPlugin instead and including the generated css file in my html: loader: ExtractTextPlugin.extract( { fallback: "style-loader", use: "css-loader!postcss-loader", publicPath: "/dist" })

I also had to use the webpack -p option to generate a production build

azat-io commented 7 years ago

I have the same error. Look here please: https://github.com/azat-io/static-site-generator-webpack2-example

jota commented 7 years ago

@azat-io seems like you are just missing the first param to the callback is null in your case.

Your index.js

callback('<!doctype html><html><head></head><body>It works!</body></html>')

Change to what the docs say and you should be good to go:

callback(null, '<!doctype html><html><head></head><body>It works!</body></html>')

azat-io commented 7 years ago

@jota My repository was updated. No difference:

ERROR in ReferenceError: self is not defined
    at Object.<anonymous> (evalmachine.<anonymous>:1:73734)
    at Object.<anonymous> (evalmachine.<anonymous>:1:74028)
    at e (evalmachine.<anonymous>:1:346)
    at Object.<anonymous> (evalmachine.<anonymous>:1:127841)
    at e (evalmachine.<anonymous>:1:346)
    at r.function.Object.create.t.exports.t.super_ (evalmachine.<anonymous>:1:729)
    at evalmachine.<anonymous>:1:739
    at evalmachine.<anonymous>:1:84
    at evalmachine.<anonymous>:1:223
    at ContextifyScript.Script.runInContext (vm.js:32:29)
sillero commented 7 years ago

The issue here is that, with this plugin, the entry point is loaded in node's context, and that's why you can use a globals property when initializing the plugin to avoid these kind of errors. When using webpack-dev-server, your entry point becomes the dev-server client JS, which is supposed to load in the browser's context, so it's filled with self, window, WebSocket and other stuff.

The best way to deal with this is to just run the plugin on a normal build process as mentioned earlier, when not using webpack-dev-server (usually production).

If for some reason this is really what you want to do, the quick/easy way out is to load globals with something like jsdom, which will add everything a browser context has, like this:

new StaticSiteGeneratorPlugin({
    paths: ....,
    globals: require('jsdom').jsdom().defaultView
})
tharnach commented 7 years ago

@ivebencrazy I'm having the same problem with isomorphic-fetch. Did you have any success resolving this before I dig in?

bpevs commented 7 years ago

@tharnach So I figured it out. The problem is actually caused by Webpack target: https://webpack.js.org/configuration/target/#target

Basically, packages that are supposed to be able to run in node AND web environments (like isomorphic-fetch), have to deal with these environments separately, and many times have separate builds for both. The thing is that when you're building with Webpack for a web application, you probably have the target set to "web", so the package will act like there's a browser there, when there isn't. So our application is telling all of our dependencies that we're running in a browser, but static-site-generator-webpack-plugin is actually running in node!

There are two ways to solve this for real:

1. Change the Target

Webpack Config adjustments for static site creation:

{
  target: "node", // <- NOT "web"
  plugins: [
    new StaticSiteGeneratorPlugin({
      paths: prerenderedPaths
    })
  ]
}

1.5 For Universal/Isomorphic Sites, use Two Builds

For universal/isomorphic sites and applications, you should probably use two builds, one for the static site, and one for the client code. Use a node target for building the html files with static-site-generator-plugin, and then use a web target WITHOUT the static-site-generator-plugin for your client javascript. This kind of makes sense anyway, since in general, bundling a normal universal app requires building the node stuff and the web stuff separately...

Webpack Config adjustments for client code:

{
  target: "web",
  plugins: [] // <- NO StaticSiteGeneratorPlugin
}

2. Run static-site-generator-webpack-plugin as if target is node

If we want to update this plugin to prevent this from happening, it would probably be a sane default for static-site-generator-webpack-plugin to assume a node target while building html. This seems like something that a bored/motivated person could look into (I don't know a ton about building webpack plugins, and I'm too lazy to learn this right now) 😆

This way, the plugins that are meant to be isomorphic/universal, and tell that they're in a node environment, and adjust accordingly.

Hacky Way

There is, of course, always a hacky way as well.... 😛

if (typeof document !== "undefined") {
    require("isomorphic-fetch");
}

if (typeof fetch == "undefined") {
    global.fetch = function() { return Promise.resolve() };
}

fetch("https://www.somethingsomethingurl.com")
    .then(function(response) {
        console.log(response);
    });
Birowsky commented 7 years ago

Unfortunately, target: 'web' didn't fix it for me. Is there anywhere a working webpack example project with this plugin?

Adding inline: false to devServer fixed it for me.

https://stackoverflow.com/a/41492420/592641

bpevs commented 7 years ago

@Birowsky I'm not sure what you mean? It sounds like you got your client-only build working, if you got it working with devServer. For the static site generation, target needs to NOT be web, as I explained in my last comment.

Birowsky commented 7 years ago

@ivebencrazy sorry i wasn't clear. I needed both for it to work. target: web and devServer.inline: false

bpevs commented 7 years ago

Ah! I didn't notice that you had edited it is all. Glad you found a solution!

dbrrt commented 7 years ago

Maybe it'd be nice now to have an up-to-date working example available under the plugin repository?