Snowpack: Pika CLI-compatible React version?

Created on 15 Jun 2019  路  11Comments  路  Source: snowpackjs/snowpack

My goal is ultimately to get React-based libraries working with a command-line Pika setup, which installs modules locally into ./web_modules/ [1].

An example of this would be react-router-dom or styled-components, both of which depend on the 'react' package, and probably a lot of libraries that start with 'react-'.

This morning I just learned about these libraries that exist to make React compatible with Pika and/or ESM:

How can these be used to create web modules for libraries that depend on React?

More specifically, if a package such as styled-components is actually doing import React from 'react', wouldn't I have to modify the package locally to refer either to import React from '@pika/react' or import React from 'es-react'?

And wouldn't I need to do this for every package that depends on React? I think I counted about 15 in my client project.

[1] Actually --dest ./public/web_modules/ for what it's worth, since I want to just rsync all of ./public instead of having any public files side by side with package.json, node_modules etc. The former being the convention in Pika's examples confuses me since the latter seems like a better practice.

Most helpful comment

@FredKSchott Got it working with the following steps:

  • npm install -P react@npm:@reactesm/react
  • npm install -P react-dom@npm:@reactesm/react-dom
  • Add react and react-dom to webDependencies if present

And it works!

All 11 comments

  • If you're using Pika CDN: Just rely on https://www.npmjs.com/package/@pika/react &
    https://www.npmjs.com/package/@pika/react-dom, all react components on the CDN are also importing these so you'll all share one version.
  • If you're using @pika/web: That's a bit trickier, React isn't written in ESM so you're asking to do something that it's not really ready for yet. But, you could theoretically use an alias to install our package in place of react in your node_modules tree: npm install react@npm:@pika/react

Try those and see how they work

Thanks @FredKSchott!

The second option works, using the alias. There's only one issue to be worked around:

At the top of node_modules/react-dom/dist-es2019/react-dom.min.js, it says import React from "@pika/react"; which Pika (probably via Rollup) then inlines into the final web_modules/react-dom.js file as a full minified const React=(function(){/*super long minified React*/}());.

If I change that like to import React from "react"; right before running npm install (with your fancy prepare script hook enabled), then it does output import React from './react.js'; instead. So I've applied this change locally for the time being, but I don't know a less "unstable" long term solution to this plan. Otherwise this sounds like the right path moving forward until React gets ESM working (why is it that hard? I don't get it.)

Besides this, everything works great. React-Router-Dom installed great and works fine, so I assume in general everything else will. (Styled-Components didn't but only because their package.json's module key points to a non-browser version of their ESM code.)

Oh interesting. Those packages were meant for our CDN specifically, where we actually do want the import to point to @pika/react, so we can't change that in the code.

Does it work to install @pika/react into both places, or someone link them together via a symlink? I don't know if there is a solution, just spitballing ideas.

With your first suggestion of installing @pika/react into both node_modules/{react,@pika/react}, I can get web_modules/react-dom.js to point to import React from './@pika/react.js'; instead of inlining it.

However, this has the same problem that inlining it does: some modules pull in ./@pika/react.js and some pull in ./react.js, so that there still results in two versions of React being imported.

The concrete issue I have when I try this is that my sample code (which uses the useState hooks) breaks, throwing an exception that points to this page: https://reactjs.org/docs/error-decoder.html/?invariant=321

I'm guessing that this is caused by React having some imperative code that it runs only once when it loads, to initialize hooks or something, and therefore loading React from two sources at the same time.

Because of the nature of this issue, I'm not sure using symlinks will fix this either, because what we ultimately want to do is get react-dom to say import React from './react.js'; at the top after Pika is done turning it into a web_modules file.

I'm guessing the only way to do this is to have two separate versions of @pika/react{,-dom}, one intended for CDN and one intended for NPM & Pika/web.

Yea, you might be right. At the end of the day React still isn't built as ESM, so we're fighting against the ecosystem here.

  1. You may have some luck with preact & preact-compat
  2. Feel free to grab my react/react-dom packages and publish them yourself, with the imports fixed.

So if I were to do your second plan, and fork your two @pika/react{,-dom} repos, and only change the import line of react-dom to point to just 'react', and publish this to NPM, that should be enough of a change to get this working, right?

I'm thinking I might do that and put the links in this issue for posterity (or so you can link them however you want). Then, all people need to do to get a Pika-compatible React installed for local web_modules use would be:

$ npm install react@npm:@whatever/react
$ npm install react-dom@npm:@whatever/react-dom

That makes sense to me! And then If enough people want this, we can take another look at adding this via official support (maybe ship both versions of the file inside of @pika/react-dom).

Alternatively @FredKSchott, it looks like half the work is already done in the CDN versions of these libraries: they already have the correct React resolved, and they actually import that from https://cdn.pika.dev/_/react/v16 ... so what if Pika/web just "downloaded" these versions of any libraries we want to install, subtituting the CDN-based import for its local equivalent, e.g. "https://cdn.pika.dev/_/react/v16" -> "./react"?

The CDN is actually a less efficient version of what @pika/web gets you. Since @pika/web knows exactly what dependencies you need, it can combine shared deps into common shared chunks. The CDN doesn't know what exactly you're loading, so it can't be that smart.

@FredKSchott Got it working with the following steps:

  • npm install -P react@npm:@reactesm/react
  • npm install -P react-dom@npm:@reactesm/react-dom
  • Add react and react-dom to webDependencies if present

And it works!

Thanks for all your work on this @sdegutis! Note with instructions is now in the Readme

Was this page helpful?
0 / 5 - 0 ratings

Related issues

FredKSchott picture FredKSchott  路  6Comments

FredKSchott picture FredKSchott  路  4Comments

daniele-orlando picture daniele-orlando  路  6Comments

FredKSchott picture FredKSchott  路  6Comments

rvion picture rvion  路  6Comments