Reputation: 4212
I'm developing an ember addon which imports sass from it's dependencies. To use it I have the following in my addon -
# my-addon/package.json
...
"dependencies": {
"lib1": "^1.5.3",
"lib2": "1.2.3",
"ember-cli-sass": "^10.0.1",
"sass": "^1.23.3"
}
...
# my-addon/addon/styles/addon.scss
@import "lib1/assets/stylesheets/styles";
@import "lib2/assets/stylesheets/styles";
# my-addon/ember-cli-build.js
let app = new EmberAddon(defaults, {
// Add options here
sassOptions: {
includePaths: [
'node_modules'
]
}
});
This way, the dummy app at tests/dummy
can resolve the imports. But when I use the addon in my host app, I get
Error: Can't find stylesheet to import.
╷
1 │ @import "lib1/assets/stylesheets/styles";
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I can modify my host app's ember-cli-build.js
to
let app = new EmberAddon(defaults, {
// Add options here
sassOptions: {
includePaths: [
'node_modules/my-addon/node_modules'
]
}
});
and ideally it should work but sass runs out of memory because it tries to import everything in node_modules
of my host app. How do I make this work for both the dummy app and the host app still be able to import namespaced lib scss?
Upvotes: 2
Views: 593
Reputation: 21
Writing my addon I had the same problems!
Researching a lot and mixing the learnings, I came to the following resolution.
Describing scenario:
Writing an EmberJS Addon to provide material design components installing the library locally and only for components and behaviors that I want my addon, reuse and expose as custom ember components. Something like the adopted addon Ember paper.
Ember version and @material dependencies.
// my-addon/package.json
...
"ember-source": "~4.5.0",
"@material/theme": "^14.0.0",
"@material/typography": "^14.0.0",
"ember-cli-sass": "^11.0.1",
"sass": "^1.53.0",
...
"ember": {
"edition": "octane"
},
...
Notice that for this answer I only added @material/typography
// my-addon/app/styles/my-addon.scss
@use "@material/typography" with (
// Customize material font-family
$font-family: unquote("Any-font-you-want, sans-serif")
);
// Import material typography styles
@use "@material/typography/mdc-typography";
For the first time, I fell into the same mistake -> Add sassOptions
to ember-cli-build.jsincluding the whole
node_modulespath. But the comment that the addon-cli wrote in the
ember-cli-build` file made me realize that I was wrong.
/* This build file specifies the options for the dummy test app of this addon, located in
/tests/dummy
This build file does not influence how the addon or the app using it behave. You most likely want to be modifying./index.js
or app's build file */
To begin we should install some npm packages
"resolve": "^1.22.1",
"broccoli-funnel": "^3.0.8",
"broccoli-merge-trees": "^4.2.0",
Asynchronously resolve the module path string id into cb(err, res [, pkg]), where pkg (if defined) is the data from package.json
Given an input node, the Broccoli Funnel plugin returns a new node with only a subset of the files from the input node. The files can be moved to different paths. You can use regular expressions to select which files to include or exclude.
Copy multiple trees of files on top of each other, resulting in a single merged tree.
// my-addon/index.js
// Import packages to work with trees and paths
const path = require('path');
const resolve = require('resolve/sync');
const funnel = require('broccoli-funnel');
const { MergeTrees } = require('broccoli-merge-trees');
/*
Below you can see an array of objects representing the
material path and the component name. Notice that we only
installed the @material/typography but the component uses other
material dependencies internally.
We will merge all `scss` and `sass` files from those paths
to allow us imports the @material/typography at
#my-addon/app/styles/my-addon.scss.
Following this design, if you forget to include some path
you will receive errors saying which paths are missing.
*/
const materialPackages = [
{ name: 'theme', path: '@material/' },
{ name: 'typography', path: '@material/' },
{ name: 'feature-targeting', path: '@material/' },
];
module.exports = {
name: require('./package').name,
included: function (/* app */) {
this._super.included.apply(this, arguments);
},
treeForStyles(tree) {
let trees = [];
let pathBase;
materialPackages.forEach(function (pkg) {
pathBase = path.dirname(
resolve(`${pkg.path}/${pkg.name}/package.json`, {
basedir: __dirname,
})
);
trees.push(
// Using broccoli to return a new tree with the
// files that matches the include property rules.
// import: ['**/*.{scss,sass}']
funnel(pathBase, {
destDir: `${pkg.path}/${pkg.name}`,
include: ['**/*.{scss,sass}'],
})
);
});
// Push existing tree
tree && trees.push(tree);
// Returninng merged broccoli tress
return new MergeTrees(trees, { overwrite: true });
}
}
With this, you should be able to use the addon with its external sass files in the dummy app or in another application using the npm link or publishing the addon.
Notice that I preferred to force addon consumers to import the @import 'my-addon-scss';
. I had not test providing styles directly on the #my-addon/addon/styles/addon.scss
.
I believe this answer can start the discussion about creating ember add-ons.
I hope I receive answers to make my code better.
Upvotes: 1