gon782

gon782

'Socket' is not exported by [...]/phoenix.js when using rollup.js

So, recently I’ve had reason to dive into JS bundling and the like and I decided to try out rollup.js for this purpose because it seems simple and has some features I think seem good, like built in dead code elimination and so on.

When trying to use it together with phoenix.js (shipped with Phoenix), rollup tells me:

$ rollup -c

js/requestWait.js → ../priv/static/js/requestWait.js...
[!] Error: 'Socket' is not exported by ../../../deps/phoenix/priv/static/phoenix.js
https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module
js/requestWait.js (1:8)
1: import {Socket} from "phoenix";
           ^

My rollup.config.js looks as follows (some of the config options have been changed in countless ways based on hours of googling and failing to fix this issue):

import commonjs from "rollup-plugin-commonjs";
import babel from "rollup-plugin-babel";
import nodeResolve from "rollup-plugin-node-resolve";

export default [
  {
    input: "js/requestWait.js",
    output: {
      file: "../priv/static/js/requestWait.js",
      format: "iife",
      sourceMap: "inline",
      name: "requestWait",
    },
    plugins: [
      nodeResolve({
        jsnext: true,
        main: true,
        module: true,
        browser: true,
        preferBuiltins: false,
        customResolveOptions: {
          moduleDirectory: [
            "node_modules",
            "../../../deps/phoenix/priv/static",
            "../../../deps/phoenix_html/priv/static",
          ]
        }
      }),
      commonjs({
        // I also tried adding `phoenix.js` here just to see if it would make any difference
        include: /node_modules/,
        sourceMap: false,
        // This does nothing, neither with
        // "../../../deps/phoenix/priv/static/phoenix.js"
        // nor the way seen below
        namedExports: {
          "node_modules/phoenix/priv/static/phoenix.js": ["Socket"]
        }
      }),
      babel({
        exclude: ["/node_modules/**", "../../../deps/**"]
      }),
    ]
  }
];

Here is the .babelrc I’m using (though I’m not sure it even gets to that step before complaining):

{
  "presets": [
    [
      "env",
      {
        "modules": false
      }
    ]
  ],
  "plugins": ["external-helpers"]
}

So, does anyone who’s been using rollup with Phoenix (and also using Socket from it, I suppose, though none of the other exports seem to work either) have any idea what to do in this situation?

Marked As Solved

peerreynders

peerreynders

For completeness sake:

// assets/rollup.config.js
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';

export default {
  input: 'js/app.js',
  output: {
    file: '../priv/static/js/app.js',
    format: 'iife',
    sourcemap: true
  },
  plugins: [
    resolve(),
    commonjs({
      namedExports: {
        '../deps/phoenix': [
          'Channel',
          'Socket',
          'LongPoll',
          'Ajax',
          'Presence'
        ]
      }
    }),
    babel({
      exclude: ['node_modules/**','../deps/**'],
    })
  ]
};

i.e. one name for each name exported from the ../deps/phoenix/assets/js/phoenix.js file:

Swiper: export
 export class Channel {
 export class Socket {
 export class LongPoll {
 export class Ajax {
 export var Presence = {

which appears in the transpiled ../deps/phoenix/priv/static/phoenix.js file as:

Swiper: exports
...
 var Channel = exports.Channel = function () {
 var Socket = exports.Socket = function () {
 var LongPoll = exports.LongPoll = function () {
 var Ajax = exports.Ajax = function () {
 var Presence = exports.Presence = {

Quote:

import {foo, bar} from 'foobar';

The variables foo and bar are imported from foobar during the resolution phase — before any of the code is actually evaluated. This is possible in the ES6 Module world because the shape of the module is known in advance.

With CommonJS, on the other hand, the shape of a module is not known until after the code is evaluated. What this means is, without making significant changes to the ECMAScript language spec, it will not be possible to use Named Imports from a CommonJS module.

See also: rollup-plugin-commonjs: Custom named exports.

Alternately:

Add a module line to deps/phoenix/package.json:

  "main": "./priv/static/phoenix.js",
  "module": "./assets/js/phoenix.js",
  "repository": {

(main is assumed to be CJS while module is ESM)

together with:

// assets/rollup.config.js
import resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';

export default {
  input: 'js/app.js',
  output: {
    file: '../priv/static/js/app.js',
    format: 'iife',
    sourcemap: true
  },
  plugins: [
    resolve(),
    babel({
      exclude: ['node_modules/**'],
    })
  ]
};

for details see rollup: pkg.module

Also Liked

peerreynders

peerreynders

FYI: "node_modules/phoenix/priv/static/phoenix.js": ["Socket"]

Did you add this folder/file yourself as part of your troubleshooting process? Because the standard package.json redirects all references to

  "dependencies": {
    "phoenix": "file:../deps/phoenix",
    "phoenix_html": "file:../deps/phoenix_html"
  },

Is there any possibility that this is rollup’s way of saying that it can’t find phoenix.js?

For what it’s worth here are the configuration files from my quick and dirty experiment a year ago (older version of rollup and Phoenix 1.2)

rollup.config.js (in the highest level directory)

import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import babel from 'rollup-plugin-babel';

export default {
  entry: "web/static/js/app.js",
  format: "iife",
  plugins: [
    resolve({
      browser: true,
      preferBuiltins: false,
      customResolveOptions: {
        moduleDirectory: [
          "deps/phoenix/priv/static",
          "deps/phoenix_html/priv/static"
        ]
      }
    }),
    commonjs({
      ignoreGlobal: true
    }),
    babel({
      exclude: [
        'node_modules/**',
        'deps/**'
      ]
      // for everything else use .babelrc
    })
  ],
  dest: "priv/static/js/app.js"
}

.babelrc

{
  "presets": [
    ["latest", {
      "es2015": {
        "modules": false
      }
    }]
  ],
  "plugins": ["external-helpers"]
}

package.json

{
  "repository": {},
  "license": "MIT",
  "scripts": {
    "watch": "npm-run-all --parallel watch:*",
    "build:assets": "rsync -r ./web/static/assets/ ./priv/static",
    "build:css": "cat ./web/static/css/phoenix.css ./web/static/css/app.css > ./priv/static/css/app.css",
    "watch:css": "watch 'npm run build:css' ./web/static/css/",
    "build:js": "rollup -c",
    "watch:js": "rollup -c -w",
    "build": "npm run build:js && npm run build:css"
  },
  "dependencies": {
    "phoenix": "file:deps/phoenix",
    "phoenix_html": "file:deps/phoenix_html"
  },
  "devDependencies": {
    "babel-plugin-external-helpers": "^6.22.0",
    "babel-preset-latest": "^6.24.1",
    "npm-run-all": "^4.0.2",
    "rollup": "^0.41.6",
    "rollup-plugin-babel": "^2.7.1",
    "rollup-plugin-commonjs": "^8.0.2",
    "rollup-plugin-node-resolve": "^3.0.0",
    "rollup-watch": "^3.2.2",
    "watch": "^1.0.2"
  }
}
Nicd

Nicd

Here’s my rollup.config.js that works for me with Phoenix 1.3:

import sourcemaps from 'rollup-plugin-sourcemaps';
import resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';

export default {
  plugins: [
    sourcemaps(),
    resolve(),
    babel(),
    commonjs({
      namedExports: {
        'deps/phoenix/priv/static/phoenix.js': ['Socket']
      }
    })
  ]
};

peerreynders

peerreynders

In your requestWait.js try not using destructuring for imports.

import phx from "phoenix";
const Socket = phx.Socket;

The other thing to try it to use deps/phoenix/assets/js/phoenix.js and pipe it through babel in case the transpiled version in deps/phoenix/priv/static/phoenix.js (i.e. remove that one from the package.json, etc.) is causing the problem.

peerreynders

peerreynders

This is the workaround:

// asset/js/socket.js
// To use Phoenix channels, the first step is to import Socket
// and connect at the socket path in "lib/web/endpoint.ex":
import phx from "phoenix";
const Socket = phx.Socket;

or even

import phx from "phoenix";
const { Socket } = phx;

For some background on the issue see
https://medium.com/the-node-js-collection/an-update-on-es6-modules-in-node-js-42c958b890c#fa77

I was able to replicate the error on a vanilla Phoenix 1.3.2 install.

rollup v0.57.1
bundles js/app.js → ../priv/static/js/app.js...
[!] Error: 'Socket' is not exported by ../deps/phoenix/priv/static/phoenix.js
https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module
js/socket.js (6:8)
4: // To use Phoenix channels, the first step is to import Socket
5: // and connect at the socket path in "lib/web/endpoint.ex":
6: import {Socket} from "phoenix"
           ^
7: 
8: let socket = new Socket("/socket", {params: {token: window.userToken}})

assets/package.json

{
  "repository": {},
  "license": "MIT",
  "scripts": {
    "build:css": "cat ./css/phoenix.css ./css/app.css > ../priv/static/css/app.css",
    "watch:css": "watch 'npm run build:css' ./css",
    "build:js": "rollup --config",
    "watch:js": "rollup --config --watch",
    "watch": "npm run watch:css & npm run watch:js"
  },
  "dependencies": {
    "phoenix": "file:../deps/phoenix",
    "phoenix_html": "file:../deps/phoenix_html"
  },
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-plugin-external-helpers": "^6.22.0",
    "babel-preset-env": "^1.6.1",
    "rollup": "^0.57.1",
    "rollup-plugin-babel": "^3.0.3",
    "rollup-plugin-commonjs": "^9.1.0",
    "rollup-plugin-node-resolve": "^3.3.0",
    "watch": "^1.0.2"
  }
}
// assets/rollup.config.js
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';

export default {
  input: 'js/app.js',
  output: {
    file: '../priv/static/js/app.js',
    format: 'iife',
    sourcemap: true
  },
  plugins: [
    resolve(),
    commonjs(),
    babel({
      exclude: ['node_modules/**','../deps/**'],
    })
  ]
};

assets/js/.babelrc

{
  "presets": [
    ["env", {
      "modules": false
    }]
  ],
  "plugins": ["external-helpers"]
}

config/dev.exs

...
  watchers: [npm: ["run", "watch", cd: Path.expand("../assets", __DIR__)]]
...
silently

silently

Hello,

In case it helps someone, when I upgraded Node from 7x to 8x, this error re-appeared despite of the namedExports setting. Adding the include property fixed it, is here an extract:

commonjs({
  include: ['node_modules/**', '../deps/**'],
  namedExports: {
    '../deps/phoenix/priv/static/phoenix.js': ['Presence', 'Socket'],
    './node_modules/react/index.js': ['createElement', 'Children', 'Component']
  }
})

Where Next?

Popular in Questions Top

pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement