Snowpack compatibility

Has anyone had success with snowpack in a PureScript project?

I’m exploring migrating this template, which works with parcel, but I’m not sure how to modify the entry point:

//index.js
require("../output/Main/index.js").main();

As is, I’m getting a require is not defined error with snowpack.

Attempted to fix by editing index.js and index.html like so:

//index.js
import("../output/Main/index.js").main();

Added type="module" to index.html:

<script type="module" src="./index.js"></script>

But these don’t work because output/Main/index.js isn’t a ES Module, right?

//output/Main/index.js
//...
module.exports = {                                                                                       
    main: main                                                                                           
}; 

We’d need it to look like:

//output/Main/index.js
//...
export {
    main
};

Would this be more straightforward with ES module output (planned for 0.15)?

Reasons for giving snowpack a try are:

  • Parcel lacks config flexibility for more complex projects, especially if paths are used and manipulated within the PS code. Parcel will flatten directory structures and mangle names.
  • Webpack took a way longer time than anticipated to setup for dev builds, and I’m expecting another deep dive is required for production builds.
  • Esbuild doesn’t play nice with my dev server and I keep getting broken pages with automatic rebuild.
1 Like

This suggests that CommonJS is supported for npm modules: https://www.snowpack.dev/#import-npm-packages

It also looks like there also at least used to be a way to make CommonJS work through a config option: https://github.com/pikapkg/snowpack/issues/62

So it seems that snowpack supports CommonJS now for whatever it considers to be dependencies, so perhaps you could convince it that the PureScript output directory is a dependency of your app and get things working that way.

I have been meaning to look into Snowpack (using a version of the compiler which includes the es modules PR) once 0.14 is out. I think it’s very exciting. I haven’t used it at all yet, though. I suspect it will indeed be easier with ES modules. You could try using Snowpack with that branch now if you wanted?

1 Like

I’m not able to build the kl0tl:es-modules branch from this PR. Example error:

purescript> /home/miles/projects/purescript/complier/.stack-work/dist/x86_64-linux-tinfo6/Cabal-2.4.0.1/build/Language/PureScript/CST/Parser.hs:149:15: error:
purescript>     Not in scope: type constructor or class ‘Kind’
purescript>     |
purescript> 149 | happyIn42 :: (Kind ()) -> (HappyAbsSyn t109)
purescript>     | 

Do I need a stack clean? Wanted to double-check before committing to a long build.

Also, that branch is based on 13.6, and I don’t want to miss out on all the great stuff in 13.8 if I use this custom build in my workflow. Hoping that rebasing this branch on 13.8 isn’t a rabbit hole.

It looks to me like you do need a stack clean. You could mention on the PR that you’d like to try it out and would the author mind rebasing, maybe? They’ll need to rebase it at some point anyway.

Looks like you’re not the first to have this issue: https://github.com/purescript/purescript/pull/3791#issuecomment-618595372

1 Like

I think in general stack is bad about invalidating the output of happy.

I’ve gotten past the initial blocker, but discovered that snowpack needs the FFI JS code to use ES Modules too.

For example, in purescript-prelude/src/Record/Unsafe.js (written to output/Record.Unsafe/foreign.js), we need this CommonJS code:

// Incompatible with snowpack
exports.unsafeHas = function (label) {
  return function (rec) {
    return {}.hasOwnProperty.call(rec, label);
  };
};

to use ES Module syntax instead:

// Works with snowpack
const unsafeHas = function (label) {
  return function (rec) {
    return {}.hasOwnProperty.call(rec, label);
  };
};
export {
  unsafeHas
};

Here’s the project repo for anyone who’d like to work on this some more.

I suspect this would eliminate many of the performance benefits of snowpack, since any tiny change to output would require a full re-bundle. Ideally, snowpack would just re-serve what gets modified in output on a per-file basis.

Correction. I was confused by seeing the 13.6 tag in the build log. That branch is actually closer to 14.0 than 13.8. There are only a few minor 13.8 commits missing. FYI, using this custom build requires a 14.0-compatible package set.

Perhaps you might be able to set up something like https://github.com/tbranyen/babel-plugin-transform-commonjs to transform commonjs FFI modules to ES modules? I suppose it’s a bit unfortunate in that it sort of adds a new build step when the aim here is presumably to reduce the number of build steps.

1 Like