Cannot use local js library with Phoenix

I try to use third party JS like Moment.js, I followed the guide.

So, I added import moment from 'moment'; to my app.js.
Moment is well added to app.js in static/assets/ but when I want to use it in Liveview template or layout with or without Alpine JS I have the Uncaught ReferenceError: moment is not defined.

When I use the CDN (<script src='URL' />) in the layout it works well, but not with npm packages…

Thanks for your help

How are you trying to use it? Can you show some examples?

I can only assume that when you add it directly via the script tag, the library attaches itself to the window object, thus why it works. In your app.js, add it as a global variable: window.moment = moment;

In my root layout I have:

<!DOCTYPE html>
<html lang="en">
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <%= csrf_meta_tag() %>
    <%= live_title_tag assigns[:page_title] %>
    <link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
    <script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
    <div class="min-h-full">
        <main class="flex-1">
          <%= @inner_content %>

and in app.js

import moment from 'moment';

window.moment = moment;

When I load my page I have Uncaught TypeError: window.moment is not a function

I tried with console.log(window.moment) but it prints undefined

When you use window.moment in the inline script, the app.js probably hasn’t loaded yet. So you need to use document.readyState or DOMContentLoaded event to make sure that the scripts have been loaded first.


Thanks, it was an initialization problem :smiling_face:

1 Like