Using newly installed JS library

To demonstrate - lets say we want to use this code that already works:


<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>Just some random JS code with lodash/fp</title>
  </head>
  <body>
    <pre id ="displayArea"></pre>
    <script type="text/javascript"
            src="https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)"></script>
    <script type="text/javascript">
     /*
        works with Chrome Version 60.0.3112.101 (Official Build) (64-bit)
        lodash/fp code re-purposed from:
        https://simonsmith.io/dipping-a-toe-into-functional-js-with-lodash-fp/#one-more-example
     */
     const displayArea = document.getElementById('displayArea');
     const items = [
       {name: 'baz'},
       {name: 'foo'},
       {name: 'bar'},
       {name: 'bar'},
       {name: 'foo'},
     ];
     const getBars = _.filter(
       _.flow(
         _.get('name'),
         _.isEqual('bar')
       )
     );

     displayArea.textContent = JSON.stringify(
       getBars(items)
     );

    </script>
  </body>
</html>

Spin up a practice project:

$ mix phx.new myapp --no-ecto

Now go into myapp/lib/myapp_web/templates/page/index.html.eex and add the target <pre> element:

<div class="jumbotron">
  <h2><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h2>
  <p class="lead">A productive web framework that<br />does not compromise speed and maintainability.</p>
</div>

<!-- BEGIN: add this -->
<div>
  <pre id="displayArea"></pre>
</div>
<!-- END add this -->

<div class="row marketing">

To make things a bit more interesting - in myapp/assets/js create a new file my-module.js (learn more and then some):

// file: myapp/assets/js/my-module.js
                           // https://github.com/lodash/lodash/wiki/FP-Guide
import _ from "lodash/fp"; // Note "_" is now a local variable 
                           // inside the module - NOT a global
export default _.filter(
  _.flow(
    _.get('name'),
    _.isEqual('bar')
  )
); // i.e. this module exports exactly one function

Now to the end of app.js already found in myapp/assets/js append some code:

...
// to also remove its path from "config.paths.watched".
import "phoenix_html"

// Import local files
//
// Local files can be imported directly using relative
// paths "./socket" or full ones "web/static/js/socket".

// import socket from "./socket"

// BEGIN -- appended code
import getBars from "./my-module"; // i.e. giving the function exported 
                                   // by my-module.js the name "getBars"
const displayArea = document.getElementById('displayArea');
const items = [
  {name: 'baz'},
  {name: 'foo'},
  {name: 'bar'},
  {name: 'bar'},
  {name: 'foo'},
];

displayArea.textContent = JSON.stringify(
  getBars(items)
);
// END -- appended code

Make sure your current working directory is myapp and fire up the phoenix server with:

$ mix phx.server

and point your browser to http://localhost:4000/. The page will display - but the textContent of the added <pre> element is empty - checking the JavaScript console reveals some errors.

At another command prompt ensure that your working directory is myapp/assets and then issue the following command:

$ npm i lodash

At this point the phoenix page should reload and you should finally see

[{"name":"bar"},{"name":"bar"}]

in the added <pre> element.

Bonus: in myapp/assets/js/app.js you may have noticed

import "phoenix_html"

Now just like lodash it comes from myapp/assets/node_modules - but not exactly. Looking at myapp/assets/node_modules/phoenix_html it becomes clear that it’s a link rather than a folder and looking at myapp/assets/package.json it becomes clear why npm created it:

...
  },
  "dependencies": {
    "lodash": "^4.17.4",
    "phoenix": "file:../deps/phoenix",
    "phoenix_html": "file:../deps/phoenix_html"
  },
  "devDependencies": {
...

myapp/deps/phoenix_html contains among other things a package.json:

{
  "name": "phoenix_html",
  "version": "2.10.4",
  "main": "./priv/static/phoenix_html.js",
  "repository": {
  },
  "files": ["LICENSE.md", "package.json", "priv/static/phoenix_html.js"]
}

which essentially tells npm to use myapp/deps/phoenix_html/priv/static/phoenix_html.js.

So in this roundabout way

import "phoenix_html"

actually imports myapp/deps/phoenix_html/priv/static/phoenix_html.js.

Now be sure to review the Phoenix Static Assets Guide and if you decide to stay with Brunch as the asset management tool to give the Brunch Guide a good look (better yet, work through it). That being said Phoenix can be adapted to other tools.

9 Likes