phoenixframework / phoenix

Peace of mind from prototype to production
https://www.phoenixframework.org
MIT License
21.35k stars 2.87k forks source link

Phoenix.js doesn't work with snowpack #4160

Closed ohmree closed 3 years ago

ohmree commented 3 years ago

Environment

Expected behavior

After setting Phoenix up to use yarn and snowpack, Phoenix's named imports (Socket, LiveSocket) should work as expected when developing with snowpack.

Actual behavior

The browser can't find the imports - chromium's error message (which is a bit more specific than firefox's) is:
Uncaught SyntaxError: The requested module '../_snowpack/pkg/phoenix.js' does not provide an export named 'Socket'

I have a hypothesis as to why this is happening: since the main entry in Phoenix's package.json points to a webpack-bundled version, I think whatever webpack's doing to the raw imports is interfering with snowpack (or esbuild)'s ability to detect the imports and rewrite them to use its static asset path (by default it's /_snowpack/pkg).

Here are a few solutions I could think of:

dbernheisel commented 3 years ago

I encountered this with Vite, and what fixed it for Phoenix and LiveView was specifying the "module" key in package.json with the value ./assets/js/phoenix.js file since it's written as ES modules. Likewise, LiveView's package.json needed the same adjustment and also needed to specify the morphdom dependency. Vite (and I think Snowpack and Rollup) will prefer this key since they are looking for ES modules. Other systems would continue looking at "main" which is the bundled version.

Maybe a better long-term solution is to consolidate Phoenix's assets/package.json into the root package.json.

Phoenix: https://github.com/dbernheisel/phoenix/commit/9dab39f7de0a517a44e35d3756c47a1a45037960 LiveView: https://github.com/dbernheisel/phoenix_live_view/commit/757d1676b8cbbe34566781285f14e115412749b6

I am planning on submitting a PR but I wanted to get into a better place with Vite to find if there are any other modifications needed for this type of JS build system.


But if that doesn't work out for some reason, you could try something like this without the adjustments above:

import * as Phoenix from "phoenix";
const { Socket } = Phoenix;
import * as LiveView from "phoenix_live_view";
const { LiveSocket } = LiveVIew;

EDIT -- added clarity.

chrismccord commented 3 years ago

I am not at all familiar with snowpack, but I would be interested in a simple PR that fixes the issue while not harming existing es6 + global window exports. Closing in the meantime as snowpack support is not something we maintain ourselves but feel free to submit a PR. Thanks!

ohmree commented 3 years ago

@dbernheisel Huh, I didn't think of doing import * as name from "module".
While it didn't work for me, it did inspire me to find something that does work:

import phoenix from "phoenix"
const {Socket} = phoenix
import LiveSocket from "phoenix_live_view"

@chrismccord Fair enough, for now I'll use the solution I found while waiting for @dbernheisel to make a PR with his changes :smile:

dbernheisel commented 3 years ago

Should be resolved for Phoenix with #4191. LiveView still needs it tho