Phoenix and brunch

Hi *, I’m battling as usual with the asset building process: no matter the framework I always find these tools incredibly hard to grasp.
What I’m trying to do is probably the easiest thing someone can do with brunch: install a js library using npm and include the javascript and the css. The library is https://www.npmjs.com/package/jquery.json-viewer
Now I managed to install it correctly and I have 2 new files under node_modules/jquery.json-viewer/json-viewer/jquery.json-viewer.css and node_modules/jquery.json-viewer/json-viewer/jquery.json-viewer.js
I’ve tried 1 million solutions but I have no idea how 2 include these 2 in my app, I whitelisted “jquery.json-viewer” but that’s it, I’m completely stuck. The documentation is very sparse (you search “brunch” on google :p) and I can’t find the important bit that explains how to solve this simple task.
Can someone help me?

ngw

3 Likes

Two good starting points

Two potential issues come to mind right off the top of my head:

  • Review your brunch-config.js - in your experiments it may have gotten compromised. Pay particular attention to the files property. As far as I can tell the default phoenix configuration will simply “stuff” any JS code (as separate modules) it can find into js/app.js - and brunch seems to include code under node_modules as well.
  • The JavaScript code may not work/be visible without the CSS file which right now is stuck under node_modules. And even if brunch manages to somehow include it into the phoenix default css/app.css relative URLs could break.

My recommendation is to start with a vanilla brunch project and try to get a brunch-only jquery.json-viewer demonstration app up and running. That should give you a feel for how brunch works and may point you in the right direction for your Phoenix project.

1 Like

I feel your pain.

Yes, it’s the very simple problems that are the worst. Also, you may have been code-blinded if you’ve been working on it awhile.

This may be true…but is it? From the brunch site on NPM integration:

NPM integration is enabled by default starting Brunch 2.3 so there’s no additional setup!
Simply npm install --save your front-end packages as you normally would, require them in your app, and Brunch will figure out the rest.

Did you remember to use the --save flag? Perhaps brunch is working off of package.json. Also, do you have a require or import somewhere in your valid js code? I’m not sure about brunch, but I know webpack doesn’t include dependencies if you don’t require them.

These are my default things I like at when I’m having trouble with the dependency not getting into the pipeline. (I forget --save way too often). :neutral_face:

2 Likes

It’s not an issue with npm or Brunch, but the author of that package.

Essentially, the author forgot to specify the entry point of the app, meaning that if you require it, you’ll get an error because there’s “nothing” to require or import.

For the JavaScript, you want to do this:

const JSONViewer = require('jquery.json-viewer/json-viewer/jquery.json-viewer.js')

or

import JSONViewer from 'jquery.json-viewer/json-viewer/jquery.json-viewer.js'

However, you’ll get an error that jQuery is undefined, because again the package author has not written this package to be imported or required through npm. He/she assumes you’ll put it in a script tag under a jQuery script tag (jQuery is assumed to be in global scope).

So it’s a broken package and your only solution is to download the CSS and JS files, though that will break too because the JS file doesn’t import jQuery, it expects it in global scope.

Sorry :confused:

1 Like

Wow, that is really broken and entirely does not follow the npm module packaging guidelines… o.O

Either way, an easy work-around:

import jQuery = from "jquery";
global.jQuery = jQuery; // Or window.jQuery = jQuery; or whatever
import JSONViewer from 'jquery.json-viewer/json-viewer/jquery.json-viewer.js';
1 Like

Babel hoists all imports to the top - so the assignment occurs too late to have the desired effect. Other problems:

  • The github version is more up to date than the one included in the npm package (which doesn’t support the conversion options properly).
  • The demo uses jQuery 2.1.3. Seems jQuery 3.x installs click handlers in a different way (i.e. delayed) so immediately triggering the installed click handler in the manner the demo performs it doesn’t work with 3.x.

Nevertheless:

web/static/js/app.js:

// web/static/js/app.js
import 'phoenix_html'
import jQuery from 'jquery';
import {run} from 'web/static/js/loadviewer';

document.addEventListener('DOMContentLoaded', () => {
  window.jQuery = jQuery;
  window.$ = jQuery;

  run();

  // Display JSON sample on load
  // -- setTimeout needed for jQuery 3.x
  setTimeout(function () {
    $('#btn-json-viewer').click();
  }, 0);
});

/* using Phoenix 1.2.1 
   $ mix phoenix.new --no-ecto json_view
   $ cd json_view 
   $ npm install --save jquery
   $ npm install --save jquery.json-viewer

   - copy "jquery.json-viewer.js" from github 
       over "node_modules/jquery.json-viewer/json-viewer/jquery.json-viewer.js"
   - create web/static/js/loadviewer.js
   - update web/static/js/app.js
   - update web/templates/page/index.html.eex
   - update brunch-config.js
   - - add npm: styles
 */

web/static/js/loadviewer.js:

// web/static/js/loadviewer.js

function transformToHtml () {
  let input, options;

  try {
    input = eval('(' + $('#json-input').val() + ')');

  } catch (error) {
    return alert("Cannot eval JSON: " + error);
  }

  options = {
    collapsed: $('#collapsed').is(':checked'),
    withQuotes: $('#with-quotes').is(':checked')
  };
  $('#json-renderer').jsonViewer(input, options);
} // end transformToHtml


export function run () {
  // force load of jquery.json-viewer
  let jsonViewer = require('jquery.json-viewer/json-viewer/jquery.json-viewer.js');

  /*  Note: jquery.json-viewer.js has been updated on github
      BUT NOT in the npm package - so the file hjas to be manually
      copies to support the "options" object properly 
   */

  $(function () { $('#btn-json-viewer').click(transformToHtml); });
}

web/templates/page/index.html.eex:

<!-- web/templates/page/index.html.eex -->
<div style=" margin: 0 100px; font-family: sans-serif;">
  <h1>
    <a href="https://github.com/abodelot/jquery.json-viewer">jQuery json-viewer</a>
  </h1>
  <textarea id="json-input" autocomplete="off" style="width: 100%; height: 200px;">
{
  "id": 1001,
  "type": "donut",
  "name": "Cake",
  "description": "http://en.wikipedia.org/wiki/Doughnut",
  "price": 2.55,
  "available": {
    store: 42,
    warehouse: 600
  },
  "topping": [
    { "id": 5001, "type": "None" },
    { "id": 5002, "type": "Glazed" },
    { "id": 5005, "type": "Sugar" },
    { "id": 5003, "type": "Chocolate" },
    { "id": 5004, "type": "Maple" }
  ]
}
  </textarea>
  <p>
    Options:
    <label><input type="checkbox" id="collapsed" />Collapse nodes</label>
    <label><input type="checkbox" id="with-quotes" />Keys with quotes</label>
  </p>
  <button id="btn-json-viewer" title="run jsonViewer()">Transform to HTML</button>
  <pre id="json-renderer" style="border: 1px solid #aaa; padding: 0.5em 1.5em;"></pre>
</div>

brunch-config.js:

exports.config = {
  files: {
    javascripts: {
      joinTo: "js/app.js"

    },
    stylesheets: {
      joinTo: "css/app.css",
      order: {
        after: ["web/static/css/app.css"] // concat app.css last
      }
    },
    templates: {
      joinTo: "js/app.js"
    }
  },

  conventions: {
    assets: /^(web\/static\/assets)/
  },

  // Phoenix paths configuration
  paths: {
    // Dependencies and current project directories to watch
    watched: [
      "web/static",
      "test/static"
    ],

    // Where to compile files to
    public: "priv/static"
  },

  // Configure your plugins
  plugins: {
    babel: {
      // Do not use ES6 compiler in vendor code
      ignore: [/web\/static\/vendor/]
    }
  },

  modules: {
    autoRequire: {
      "js/app.js": ["web/static/js/app"]
    }
  },

  npm: {
    enabled: true,
    // --- ADD styles property MANUALLY ---
    styles: {
      'jquery.json-viewer': ['json-viewer/jquery.json-viewer.css']
    }
  }
};

Resulting package.json:

{
  "repository": {},
  "license": "MIT",
  "scripts": {
    "deploy": "brunch build --production",
    "watch": "brunch watch --stdin"
  },
  "dependencies": {
    "jquery": "^3.1.1",
    "jquery.json-viewer": "^1.1.0",
    "phoenix": "file:deps/phoenix",
    "phoenix_html": "file:deps/phoenix_html"
  },
  "devDependencies": {
    "babel-brunch": "~6.0.0",
    "brunch": "2.7.4",
    "clean-css-brunch": "~2.0.0",
    "css-brunch": "~2.0.0",
    "javascript-brunch": "~2.0.0",
    "uglify-js-brunch": "~2.0.1"
  }
}
2 Likes