Coffeescript - oh boy I need it

Coming from Ruby On Rails it’s quite a ride to build a fresh “worktable” - like take for instance adding support for coffeescript!

In my rails repos I’d add the webpacker gem and “it just works” with me sprinkling (coffee) script all over the place - in my templates, my partials, layouts, and of cause in my assets.

With Phoenix, I try to yarn add coffeescript -D and then I add

        {
          test: /\.coffee$/,
          exclude: /node_modules/,
          use: {
            loader: 'coffee-loader',
          },
        },

to my webpack.config.js, I add a coffee-script file like page.coffee with

module.exports = class Page
  notify = (msg) ->
    alert msg

My webpack output looks like this

webpack is watching the files…

[debug] Live reload: priv/static/js/app.js
[debug] Live reload: priv/static/css/app.css
Hash: 9a46e0bdabb498444158
Version: webpack 4.41.5
Time: 6587ms
Built at: 2020-06-22 13:53:01
                Asset       Size  Chunks                   Chunk Names
       ../css/app.css   3.54 MiB     app  [emitted]        app
   ../css/app.css.map    4.5 MiB     app  [emitted] [dev]  app
       ../favicon.ico   1.23 KiB          [emitted]        
../images/phoenix.png   13.6 KiB          [emitted]        
        ../robots.txt  202 bytes          [emitted]        
               app.js    100 KiB     app  [emitted]        app
           app.js.map    117 KiB     app  [emitted] [dev]  app
Entrypoint app = ../css/app.css app.js ../css/app.css.map app.js.map
[0] multi ./js/app.js 28 bytes {app} [built]
[./css/app.scss] 39 bytes {app} [built]
[./js/app.js] 1.34 KiB {app} [built]
[./js/page.coffee] 150 bytes {app} [built]
    + 5 hidden modules
Child mini-css-extract-plugin node_modules/css-loader/dist/cjs.js!node_modules/sass-loader/dist/cjs.js!node_modules/postcss-loader/src/index.js!css/app.scss:
    Entrypoint mini-css-extract-plugin = *
    [./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./node_modules/postcss-loader/src/index.js!./css/app.scss] ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./node_modules/postcss-loader/src!./css/app.scss 3.7 MiB {mini-css-extract-plugin} [built]
        + 1 hidden module

and I start by importing it in my app.js with import Page from './page.coffee' but I am not able to do something like

<!-- ./lib/fish_web/templates/layout/root.html.leex --->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Fish · </title>
    <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
    <link rel="stylesheet" href="https://rsms.me/inter/inter.css">
    <%= csrf_meta_tag() %>
    <script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
  </head>
     ....
    </div>
    <%= render_shared "footer.html", assigns %>
    <script>
      Page.notify('fisk')
    </script>
  </body>
</html>

and what is even more annoying is that I am neither able to do

<!-- ./lib/fish_web/templates/layout/root.html.leex --->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Fish · </title>
    <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
    <link rel="stylesheet" href="https://rsms.me/inter/inter.css">
    <%= csrf_meta_tag() %>
    <script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
  </head>
     ....
    </div>
    <%= render_shared "footer.html", assigns %>
    <script>
      $ ->
        Page.notify 'well'
    </script>
  </body>
</html>

I realize this question is borderline Webpack, Javascript but the integration with Phoenix should belong here I guess?

The integration for webpack into phoenix is essentially this:

  • generators for a basic webpack pipeline (everything in /assets)
  • starting webpack in development with the phoenix server (a single line in config/dev.exs)

Phoenix itself is completely agnostic to how you build your static assets and just takes what is put into priv/static/. There’s nothing of an integration like webpacker for phoenix. Therefore yes, this is a webpack question.

You’ve two issues here. The defer attribute on the script tag of app.js means the contents of app.js are evaluated later than your inline script. The other one is that your Page object is part of app.js, but webpack does scope all of your code. If you want to bind things to the window object you’ll need to explicitly do window.Page = Page to be able to call it in inline scripts.

3 Likes

Thank you @LostKobrakai - that made it (almost) crystal clear

I missed the defer - shoot

As for the scoping done by webpack - my “license plate” dates back when JavaScript was merely about moving dancing babies around the screen, I am afraid :cry:

Anyways, thank you again - I’ll try my luck in one of the webpack agoras

:slight_smile:

:smiley:

This made me check – Dynamic Drive is still around! Dynamic Drive DHTML Script- Snow Effect

haha - Henrik

:smiley:

yeah - that kid got us a ton of customers :laughing: