reshape/standard

Access to plugins?

Closed this issue · 12 comments

tmpfs commented

It would be cool if the option to append to the default plugins or overwrite them were available via the options.

My primary use case is to append a plugin that would look for <link rel="stylesheet"> elements and inline the style into the document head.

Thanks for any suggestions on the best way to achieve this.

tmpfs commented

Ok, I think I've worked it out.

I created a plugin like this one:

https://github.com/tmpfs/tmpfs.org/blob/master/css-inject.js

And then configured reshape like this:

reshape: (ctx) => {
  const info = htmlStandards({
    webpack: ctx,
    locals: { pageId: pageIdentifier(ctx) }
  })
  info.plugins.push(new CssInject())
  return info
}

Could be published as reshape-css-critical-path in it's own module.

What do you think to this approach?

BTW, I've noticed a few issues with the main reshape readme document appearing to be out of date. Using attributes instead of attrs and a string type instead of text type.

tmpfs commented

The problem with this approach is that when I run from a clean build the css files to inline do not exist yet, how would I hook in to ensure the css output files have been generated. A webpack plugin is not the answer it seems as I am using postcss to generate the standalone stylesheet. Maybe this question is better suited to spike which I am using...

tmpfs commented

I have worked around this by running compile twice on a clean, compile, deploy script but it would be cool if I could hook into the stylesheet file contents correctly ;) The postcss compile logic executes before the reshape plugins but I guess they are not written to disc until all compile phases are completed.

Maybe an external post-processor is a better approach?

Hi @tmpfs! Sorry for the late response here.

The way you worked it out above is exactly right, just push to the array! If you have found some inaccuracies in the reshape docs, is there any chance you'd be willing to submit a PR to fix them? Would be amazing -- trying to keep everything up to date but it's hard when you're just one guy!

So in order to get the results of the compiled stylesheet, you're correct, you would need a webpack plugin to hook in at the correct place. If you could ensure that css compilation is consistently completed before html (this seems like it would be difficult, would have to dig in to webpack for it), you could pass the data to your plugin by modifying the reshape options interactively through the plugin. This is definitely a challenge though!

Hey update, so I'm working on converting this whole system to use webpack2, and it looks like they recently added a feature where you can have hooks before/after loaders have executed. This might be the trick to making this type of feature work!

Example with postcss: https://github.com/postcss/postcss-loader/blob/master/test/webpack-plugins/rewrite.js

tmpfs commented

Thanks for the comments :)

Happy to submit PRs for the documentation updates...

Well the problem I have with webpack is that it only operates on Javascript sources which doesn't play so well with static websites generated by spike. I would have to load all the markup into javascript for webpack to process it (I think?) and then I'm not sure how that would place nicely with reshape!

So I have started playing with an idea for a tool that would post-process the spike output files performing optimization of all the assets. Why?

  • Because it would be cool if you could drop all minification from your libraries and we run this library afterwards which takes care of that. You already want to deprecate some of the minify options...
  • I don't want to wire up a gulp file for every static website project, I just want it to work out of the box with very sensible defaults.
  • I would like it to be able to transpile my project if I like before transformation and optimization.
  • I would like an easy to understand processing lifecycle.

I'm sketching this out at the moment and it's coming along quite nicely, I can take a static website and post-process a lot of common optimizations.

I need to think it through a bit more but ideally I want it to understand all the input/output files and their resources too and then maybe I can integrate this with webpack loaders.

The idea is you can use webpack loaders in non-javascript files and the resource dependency graph will be detailed enough to implement file fingerprinting (cache busting).

I'll ask for some peer review when it's a bit more stable.

I know working with webpack can be tricky, but I'm pretty confident that not tacking on extra processing and running it through webpack will ultimately be the best way to achieve this.

I have all the markup that spike already processes running through webpack without issue, which is pretty good evidence that it can and does play nice with both html and css, it's just not quite as intuitive at first as running something like gulp. That being said, the extra work behind integrating with webpack provides huge numbers of benefits when it comes to community plugins and support, speed, and optimization options.

I don't intend to remove the production options or drop minification -- they are working well. If I did remove any minify options, it would be taking them out of the standards libraries and manually adding them to the production file.

Spike is a great example of how you can process non-javascript files with webpack already, and it does come out with a perfect dependency graph (which is why it will still reload only the pages needed when you save a reshape partial, for example). There is good support for fingerprinting in webpack as well, I just haven't made it a huge priority to work it in to spike's defaults because netlify can handle it all without issue.

tmpfs commented

Cool, thanks for the information.

I have all the markup that spike already processes running through webpack without issue

Are you able to provide an example that I can inspect to show webpack processing HTML/CSS files that are not referenced from javascript please?

Sure sure.

So in spike, we scan the file tree of the project and pull the files that we need to process, than manually inject them into webpack's processing pipeline (which is why they work without having to be required from somewhere)

https://github.com/static-dev/spike-core/blob/master/lib/plugin.js#L40

Next, we let webpack do its processing through loaders etc. The key loader here is source-loader, which lets you pass any type of content through webpack without it throwing a javascript error or trying to process it. It also makes the raw source available to plugins through a special _src property. We set up the postcss and reshape loaders to have source-loader run after them to prevent errors for this very reason:

https://github.com/static-dev/spike-core/blob/master/lib/config.js#L218

Now, after the processing is done, spike will grab the compiled source and emit it as an asset through webpack:

https://github.com/static-dev/spike-core/blob/master/lib/plugin.js#L64

Then remove the source from webpack's pipeline so that it doesn't try to emit it separately:

https://github.com/static-dev/spike-core/blob/master/lib/plugin.js#L91

...that's pretty much the entire process! Spike essentially just uses webpack as a compiler -- it's able to inject any type of source (it even does this for binary files, images, etc), have it processed in any way you want through loaders by padding with the source loader, and then either let webpack make the source available through javascript, or extract it and write it yourself through webpack's emit hook.

Hope this helps! Really, spike is a very small and simple project because webpack is doing most of the work. It's only 3 files of substance, and none of them are over 300LOC.

tmpfs commented

Thanks so much for the reply - very helpful!

My primary problems arose from over-aggressive minification during production builds when using spike. Really impressed with spike, reshape etc. - thank you :)

For sure, the reshape minify plugin still needs some work. Definitely accepting contributions if you're willing to dig in. There's one large outstanding bug where it seems to be removing the page id, I'm going to have that resolved pretty soon!

tmpfs commented

Hacked a workaround for this so closing, ta.