2
votes

How do I correctly import a non-plugin npm module into Ember?

I'm trying to use the sass version of flag-icon-css with ember-cli so that the sass is being built during deploy with the rest of ember-cli-sass, but I can't figure out how to do it in an automated fashion (e.g. without manually copying files over to public).

Using ember-auto-import seems like a good place to start but it is more tailored towards javascript imports.

I have tried this configuration in ember-cli-build.js:

    'sassOptions': {
        includePaths: [
            'node_modules/flag-icon-css/sass' // flag-icon.scss
        ]
    },

It will add the styles, but it doesn't include the images used in the styles.

I have read this documentation, but it doesn't specify something more complicated than a single file.

2

2 Answers

5
votes

Just use ember-cli-sass:

  1. first add it to includePaths in your ember-cli-build.js
new EmberApp({
  sassOptions: {
    includePaths: [
      'node_modules/flag-icon-css/sass'
    ]
  }
});
  1. use it with @import "flag-icon";

Have a look in the readme.

now while this will sucessfully add the compiled sass output to your /assets/app-name.js there is no automated way to add any kind of assets to your dist folder.

In the case of flag-icon-css it will just add background-image: url(../flags/4x3/gr.svg); to your dist/assets/app-name.css, but not add the svg itself. You can manually do this with broccolis Funnel and MergeTrees:

  1. install broccoli-funnnel and broccoli-merge-trees
  2. import them in ember-cli-build.js:
const Funnel = require('broccoli-funnel');
const MergeTrees = require('broccoli-merge-trees');
  1. use them by replacing return app.toTree() in your ember-cli-build.js with
const flagIcons = Funnel('node_modules/flag-icon-css', { include: ['flags/**/*'] });
return new MergeTrees([app.toTree(), flagIcons]);

so your entire ember-cli-build.js could look like this:

'use strict';

const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const Funnel = require('broccoli-funnel');
const MergeTrees = require('broccoli-merge-trees');

module.exports = function(defaults) {
  let app = new EmberApp(defaults, {
    // Add options here
    sassOptions: {
      includePaths: [
        'node_modules/flag-icon-css/sass'
      ]
    }
  });

  const flagIcons = Funnel('node_modules/flag-icon-css', { include: ['flags/**/*'] });
  return new MergeTrees([app.toTree(), flagIcons]);
};

a short sidenote: I would usually recommend to put assets into the assets folder of your output, but in this case this wont work because the flag-icon-css expects the flags folder to be in the parent directory of the .css.

2
votes

I figured this out, but I'm not sure it's the best or easiest way. It has some drawbacks.

const EmberApp = require('ember-cli/lib/broccoli/ember-app')
const Funnel = require('broccoli-funnel')

module.exports = function(defaults) {
    const app = new EmberApp(defaults, {
        'sassOptions': {
            includePaths: [
                'node_modules/flag-icon-css/sass'
            ]
        }
    })

    const flags = new Funnel('node_modules/flag-icon-css/', {
        srcDir: 'flags',
        destDir: '/flags',
    })

    return app.toTree([flags])
}

The drawback is that the css image urls are not processed, and hardlinked to ../flags, so I have to funnel them into /flags, which is not the convention, as these assets should be compiled into public/assets/images.

This is a two-step implementation (or more steps if the npm module would be more complex). It would be preferred to include just the scss and have (an) Ember (plugin) automatically fetch the dependent resources.