Coder Social home page Coder Social logo

ember-css-modules's Introduction

ember-css-modules Actions Status Ember Observer Score

Ember-flavored support for CSS Modules. For an overview of some of the motivations for the CSS Modules concept, see this blog post.

If you have ideas or questions that aren't addressed here, try #topic-css on the Ember Discord Server.

Installation

ember install ember-css-modules

What and Why?

When you build a component, you drop a .js file and a .hbs file in your app directory, and your tooling takes care of the rest. Babel takes your fancy ES6 module and restructures it into nice browser-friendly code, while still giving you isolation and modularity guarantees. Meanwhile, the rest of the Ember CLI build pipeline picks up these new files and automatically incorporates them into your final JS artifact. And when it's time to come back and tweak your component, you (just like the Ember resolver) know exactly where those files live based just on the name of the component.

With ember-css-modules, your styling is a first-class citizen alongside your templates and JavaScript. You have one .css file per component (or route controller), in the same structure you're already using in the rest of your app. Every class you write is local to that file by default, with explicit mechanisms for opting into sharing, just like your JavaScript modules. And just like all your JS modules are automatically included in <app-name>.js, your CSS modules will automatically be included in <app-name>.css.

Usage

Simple Example

With ember-css-modules, you define styles on a per-component (or -controller) basis. You define these styles using the same file layout you use for templates; for example, in pod structure you'd put styles.css alongside template.hbs in the component's pod. The classes in that stylesheet are then automatically namespaced to the corresponding component or controller. In order to reference them, you use the local-class attribute rather than the standard class.

{{! app/components/my-component/template.hbs }}
<div local-class="hello-class">Hello, world!</div>
/* app/components/my-component/styles.css */
.hello-class {
  font-weight: bold;
}

Similarly, if you were styling e.g. your application controller, you would place your styles alongside controller.js in <podModulePrefix>/application/styles.css.

Component Colocation Example

In Octane apps, where component templates can be colocated with their backing class, your styles module for a component takes the same name as the backing class and template files:

{{! app/components/my-component.hbs }}
<div local-class="hello-class">Hello, world!</div>
/* app/components/my-component.css */
.hello-class {
  font-weight: bold;
}

Styling Reuse

In the example above, hello-class is rewritten internally to something like _hello-class_1dr4n4 to ensure it doesn't conflict with a hello-class defined in some other module.

For cases where class reuse is desired, there's the composes property. Suppose you have a title in your component that you'd like to inherit your app-wide "secondary header" styling, which itself uses generic styling shared by all headers:

/* app/styles/headers.css */
.header {
  font-weight: bold;
  text-decoration: underline;
}

.secondary-header {
  composes: header;
  color: #339;
}
/* app/components/my-component/styles.css */
.component-title {
  composes: secondary-header from 'my-app-name/styles/headers';
  background-color: #eee;
}

In the template for my-component, an element with local-class="component-title" will end up with an actual class string like _component-title_1dr4n4 _secondary-header_1658xu _header_1658xu, incorporating styles from all of the composing classes.

Note that you may also use relative paths to specify the source modules for composition.

Finally, you can compose local classes from global un-namespaced ones that are provided e.g. by a CSS framework by specifying global as the source of the class:

/* vendor/some-lib.css */
.super-important {
  color: orange;
}
/* app/components/my-component/styles.css */
.special-button {
  composes: super-important from global;
}

Programmatic Styles Access

Currently the local-class attribute is honored on HTML elements and component invocations, e.g. <div local-class="foo {{bar}}"> and {{input local-class="baz"}}. It is not (currently) supported in subexpressions like the (component) helper.

If you need to access a local class in a template in other scenarios (such as passing in a class name as a property or reusing a class from another module), there is also a local-class helper you can use. For example, the "secondary-header" example above can be written as:

{{! app/components/my-component/template.hbs }}
<div class="{{local-class 'secondary-header' from='my-app-name/styles/headers'}}">Hello, world!</div>

Note that the from parameter is optional; by default classes will come from the current module, as with the local-class attribute.

In a JavaScript context, the class mappings can also be imported directly from whatever path the corresponding CSS module occupies, e.g.

import styles from 'my-app-name/components/my-component/styles';
console.log(styles['hello-class']);
// => "_hello-class_1dr4n4"

Note: by default, the import path for a styles module does not include the .css (or equivalent) extension. However, if you set includeExtensionInModulePath: true, then you'd instead write:

import styles from 'my-app-name/components/my-component/styles.css';

Note that the extension is always included for styles modules that are part of an Octane "colocated" component, to avoid a conflict with the import path for the component itself.

Global Classes

Some libraries provide explicit class names as part of their public interface in order to allow customization of their look and feel. If, for example, you're wrapping such a library in a component, you need to be able to reference those unscoped class names in the context of your component styles. The :global pseudoselector allows for this:

.my-component :global(.some-library-class) {
  color: orange;
}

For more details on :local and :global exceptions, see the CSS Modules documentation.

Values

For exposing data other than class names across module boundaries, you can use @value.

/* app/styles/colors.css */
@value primary-color: #8af;
@value secondary-color: #fc0;
/* app/some-route-pod/styles.css */
@value primary-color, secondary-color from 'my-app-name/styles/colors';

.blurb {
  color: primary-color;
  background-color: secondary-color;
}

Note that values are also exposed on the styles object for a given module, so they are also accessible from JavaScript if you need to coordinate between the two. As a contrived example:

// app/some-route-pod/controller.js
import styles from 'app/some-route-pod/styles';

export default Ember.Controller.extend({
  logColor() {
    console.log('primary color is', styles['primary-color']);
  }
});

Glint usage

Helper {{local-class}} has proper Glint types, which allow you when using TypeScript to get strict type checking in your templates.

Unless you are using strict mode templates (via first class component templates), you need to import the addon's Glint template registry and extend your app's registry declaration as described in the Using Addons documentation:

import '@glint/environment-ember-loose';
import type EmberCssModulesRegistry from 'ember-css-modules/template-registry';

declare module '@glint/environment-ember-loose/registry' {
  export default interface Registry extends EmberCssModulesRegistry, /* other addon registries */ {
    // local entries
  }
}

Usage in Addons

You can also use ember-css-modules in addons that expose components to their consuming application. To do this you'll need to move ember-css-modules out of devDependencies and into dependencies in your addon's package.json (see issue #8).

Note also that your addon must have an addon/styles directory in order to trigger CSS processing in Ember CLI. In order for the directory to be preserved when you publish your addon, you can create an empty .placeholder file (.gitkeep won't work; by default, the .npmignore for your addon will prevent files with that name from being published).

Plugins

Ember CSS Modules has a plugin ecosystem that allows for people to bundle up common configurations and extensions for easy reuse and distribution. For example, if your organization has a common set of PostCSS plugins you always use, you could package those as a plugin and then just drop that into any Ember project and have it automatically take effect.

For details on developing your own, see the plugins mini-guide. You can also look at the following examples of what plugin implementations can look like:

You can find a list of all publicly available plugins by browsing the npm ember-css-modules-plugin keyword.

Advanced Configuration

Details about specific advanced configuration options are broken out into smaller mini-guides that each focus on a single topic:

Where to Specify Options

For applications, custom configuration for ember-css-modules may be specified in ember-cli-build.js:

new EmberApp(defaults, {
  // ...
  cssModules: {
    // config
  }
});

For addons, configuration may be specified in your addon's index.js instead:

module.exports = {
  // ...
  options: {
    cssModules: {
      // config
    }
  }
};

Extensions in Module Paths

When importing a CSS module's values from JS, or referencing it via @value or composes:, by default you do not include the .css extension in the import path. The exception to this rule is for modules that are part of an Octane-style colocated component, as the extension is the only thing to differentiate the styles module from the component module itself.

If you wish to enable this behavior for all modules, you can set the includeExtensionInModulePath flag in your configuration:

new EmberApp(defaults, {
  cssModules: {
    includeExtensionInModulePath: true,
  },
});

Scoped Name Generation

By default, ember-css-modules produces a unique scoped name for each class in a module by combining the original class name with a hash of the path of the containing module. You can override this behavior by passing a generateScopedName function in the configuration.

new EmberApp(defaults, {
  cssModules: {
    generateScopedName(className, modulePath) {
      // Your logic here
    }
  }
});

Note that addons may specify their own generateScopedName function, but otherwise they will fall back to using the one (if any) specified by the host application.

Source Maps

Ember CLI allows you to specify source map settings for your entire build process, and ember-css-modules will honor that configuration. For instance, to enable source maps in all environments for both JS and CSS files, you could put the following in your ember-cli-build.js:

sourcemaps: {
  enabled: true,
  extensions: ['js', 'css']
}

Notes

  • You should specify the css extension in your source map configuration even if you're using a different extension for your modules themselves, since the final output file will be a .css file.
  • Currently CSS source maps (for any Ember CLI preprocessor) only work for applications, not for addons. Watch ember-cli/broccoli-concat#58 for progress on that front.
  • Enabling source maps for CSS can cause Ember CLI to output an invalid comment at the end of your vendor.css file. This is harmless in many situations, but can cause issues with tools that postprocess your css, like ember-cli-autoprefixer. ember-cli/broccoli-concat#58 is the root cause of this issue as well.

Ember Support

This addon is tested against and expected to work with Ember's active LTS releases as well as the current release, beta, and canary builds.

ember-css-modules's People

Contributors

alexlafroscia avatar bobrimperator avatar buschtoens avatar camnicklaus avatar cibernox avatar dependabot[bot] avatar deverstalmage avatar devotox avatar dfreeman avatar ef4 avatar ember-tomster avatar fpauser avatar garno avatar jamescdavis avatar jasonmit avatar jessedijkstra avatar joshbranham avatar luxzeitlos avatar pattra avatar rlivsey avatar runspired avatar sergeastapov avatar skarger avatar timkendall avatar timlindvall avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ember-css-modules's Issues

Can't use container as a class name

Since updating to 0.3.0, it became impossible to use CSS class container. {{styles.container}} evaluates to Ember's container object and renders as [object Object]. There might be other properties with similar behavior.

Addon usage not work in consumer app

I move all things related with ember-css-modules and postcss stack into an addon (also along with styles), follow the instructions on readme, it looks good for both addon itself and dummy app.

After then I install this addon to consumer ember app, things from inside the addon still works, but ember-css-modules won't process styles in the consumer app (I thought it would be).

Now I have to install ember-css-modules in consumer app again, and if some settings going to change, it has to be done in two or more projects. How to solve this?

Here is the addon repo: https://github.com/choice-form/ember-choice-ui, if it helps.

Ability to override scoped name generator

Allow passing custom generateScopedName to broccoli-css-modules. Use case: we have a deeply nested component hierarchy, and including path in the generated class name would improve our DX.

Build fails with ember-engines lazyLoading enabled

I have an existing application that consumes a single, add-on based engine. Both are using ember-css-modules in the CSS stack.

"ember-css-modules": "0.6.4" is a devDependency in the consuming app and a dependency in the engine add-on. The build was working as expected at this point.

Yesterday I updated to [email protected] to try out lazy loading. Upon updating the dependencies in both the app and engine and setting lazyLoading: true in add-on/engine.js, the build now fails.

The Broccoli Plugin: [SimpleConcat] failed with:
TypeError: Cannot read property '0' of undefined
    at OutputStylesPreprocessor.eachFileWithDependencies (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/lib/output-styles-preprocessor.js:102:72)
    at OutputStylesPreprocessor.explicitDependencies (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/lib/output-styles-preprocessor.js:72:8)
    at OutputStylesPreprocessor.getHeaderFiles (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/lib/output-styles-preprocessor.js:61:27)
    at Concat.concat.build (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/lib/output-styles-preprocessor.js:48:24)
    at /Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/node_modules/broccoli-caching-writer/index.js:149:21
    at tryCatch (/Users/J/git/moltin/forge-products-engine/node_modules/rsvp/dist/rsvp.js:538:12)
    at invokeCallback (/Users/J/git/moltin/forge-products-engine/node_modules/rsvp/dist/rsvp.js:553:13)
    at publish (/Users/J/git/moltin/forge-products-engine/node_modules/rsvp/dist/rsvp.js:521:7)
    at flush (/Users/J/git/moltin/forge-products-engine/node_modules/rsvp/dist/rsvp.js:2373:5)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)

The broccoli plugin was instantiated at: 
    at Concat.Plugin (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/node_modules/broccoli-plugin/index.js:10:31)
    at Concat.CachingWriter [as constructor] (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/node_modules/broccoli-caching-writer/index.js:18:10)
    at new Concat (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/node_modules/broccoli-concat/concat.js:32:17)
    at new module.exports (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/node_modules/broccoli-concat/index.js:26:10)
    at OutputStylesPreprocessor.dynamicHeaderConcat (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/lib/output-styles-preprocessor.js:45:16)
    at OutputStylesPreprocessor.toTree (/Users/J/git/moltin/forge-products-engine/node_modules/ember-css-modules/lib/output-styles-preprocessor.js:27:21)
    at /Users/J/git/moltin/forge/node_modules/ember-cli-preprocess-registry/preprocessors.js:180:26
    at Array.forEach (native)
    at processPlugins (/Users/J/git/moltin/forge/node_modules/ember-cli-preprocess-registry/preprocessors.js:178:11)
    at module.exports.preprocessCss (/Users/J/git/moltin/forge/node_modules/ember-cli-preprocess-registry/preprocessors.js:148:10)
    at Class.compileStyles (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/models/addon.js:622:14)
    at Class.treeForAddon (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/models/addon.js:515:27)
    at Class._treeFor (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/models/addon.js:371:33)
    at Class.treeFor (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/models/addon.js:339:21)
    at /Users/J/git/moltin/forge/node_modules/ember-cli/lib/models/addon.js:254:34
    at Array.map (native)
    at Class.eachAddonInvoke (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/models/addon.js:252:24)
    at Class.buildVendorTree (/Users/J/git/moltin/forge-products-engine/node_modules/ember-engines/lib/engine-addon.js:85:36)
    at Class.buildCompleteJSTree (/Users/J/git/moltin/forge-products-engine/node_modules/ember-engines/lib/engine-addon.js:184:36)
    at Class.treeForEngine (/Users/J/git/moltin/forge-products-engine/node_modules/ember-engines/lib/engine-addon.js:277:50)
    at Class.treeFor (/Users/J/git/moltin/forge-products-engine/node_modules/ember-engines/lib/engine-addon.js:638:25)
    at /Users/J/git/moltin/forge/node_modules/ember-cli/lib/broccoli/ember-app.js:499:20
    at Array.map (native)
    at EmberApp.addonTreesFor (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/broccoli/ember-app.js:497:30)
    at EmberApp._addonTree (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/broccoli/ember-app.js:902:36)
    at EmberApp._processedVendorTree (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/broccoli/ember-app.js:947:20)
    at EmberApp._processedExternalTree (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/broccoli/ember-app.js:978:21)
    at EmberApp.appAndDependencies (/Users/J/git/moltin/forge/node_modules/ember-cli/lib/broccoli/ember-app.js:1087:30)

Ampersand operator doesn't works in addon

For example, I have styles:
.button {
&:hover { color: red }
}
and I expect .button:hover {color:red}, but ember-css-modules doesn't compile it.
For more examples I create a simple addon, please check this link

Document global class composition

Composing global classes can be super useful for interop with third-party libraries โ€“ย we should make sure that's documented (and has test coverage).

Template preprocessing(?)

Currently to reference a class name from a component/controller's corresponding CSS module, users must insert an explicit binding to a field of the styles object in their template.

<div class="{{styles.container}}">
  <span class="framework-class {{styles.text}}">Hello</span>
</div>

This has the advantage of making it very clear where the class names are coming from, but is fairly verbose. One alternative might be to introduce a dedicated attribute for local classes and then provide a Handlebars preprocessor that would transform the following template, making it equivalent to the above:

<div local-class="container">
  <span class="framework-class" local-class="text">Hello</span>
<div>

You could even make class local by default and instead make global classes the special case:

<div class="container">
  <span global-class="framework-class" class="text">Hello</span>
</div>

Would introducing such a transform even be a good idea?

Some cons:

  • It would introduce fairly magical (i.e. nonobvious) behavior
  • Handlebars AST transforms are technically a private API

Some pros:

  • Templates and CSS source more closely align; potentially better readability
  • Easier migration โ€“ย more existing styles would continue to "just work" with fewer changes

Stupid Question: Usage with link-to helper

I am struggling to find the right syntax to use this the built-in link-to helper. I have tried:

{{#link-to 'routeName' class={{styles.class-name}}}}Label{{/link-to}}
{{#link-to 'routeName' class="{{styles.class-name}}" }}Label{{/link-to}}
{{#link-to 'routeName' class=styles.class-name }}Label{{/link-to}}

And none of these work. Your hep is appreciated.

Attempts to import from a nonexistent addon fail with an unhelpful error

Similar in spirit to #59, if I have something like this:

.my-class {
  composes: something-cool from 'addon-i-havent-installed/cool-stuff';
}

I'll get an unhelpful error message of the form:

Build failed.
The Broccoli Plugin: [CSSModules] failed with:
TypeError: Cannot read property 'root' of undefined
    at resolveExternalPath (/path/to/project/node_modules/ember-css-modules/lib/resolve-path.js:45:38)
    at ModulesPreprocessor.resolvePath [as _resolvePath] (/path/to/project/node_modules/ember-css-modules/lib/resolve-path.js:15:12)
    at ModulesPreprocessor.resolvePath (/path/to/project/node_modules/ember-css-modules/lib/modules-preprocessor.js:171:15)
    at ModulesPreprocessor.resolveAndRecordPath (/path/to/project/node_modules/ember-css-modules/lib/modules-preprocessor.js:150:23)
    at CSSModules.fetchExports (/path/to/project/node_modules/broccoli-css-modules/index.js:118:27)
    at fetchImport (/path/to/project/node_modules/broccoli-css-modules/lib/link-modules.js:41:34)
    at /path/to/project/node_modules/broccoli-css-modules/lib/link-modules.js:32:20
    at Root.each (/path/to/project/node_modules/postcss/lib/container.js:114:22)
    at fetchAllImports (/path/to/project/node_modules/broccoli-css-modules/lib/link-modules.js:30:7)
    at /path/to/project/node_modules/broccoli-css-modules/lib/link-modules.js:20:24

Better would be an actual error message to the effect of "Hey, I tried to resolve addon-i-havent-installed and came up blank. Maybe you have a typo or forgot to install something?"

Build fails when hidden files are in the styles directory

If you have a hidden file like .DS_Store or .gitkeep in app/styles the build fails with the following output:

The Broccoli Plugin: [BroccoliMergeTrees] failed with:
Error: Merge error: file hidden-files-css-modules/styles/.gitkeep exists in /Users/my-user/Code/hidden-files-css-modules/tmp/broccoli_merge_trees-input_base_path-waG9v3er.tmp/0 and /Users/my-user/Code/hidden-files-css-modules/tmp/broccoli_merge_trees-input_base_path-waG9v3er.tmp/1
Pass option { overwrite: true } to mergeTrees in order to have the latter file win.
    at BroccoliMergeTrees._mergeRelativePath (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/index.js:212:17)
    at BroccoliMergeTrees._mergeRelativePath (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/index.js:238:31)
    at BroccoliMergeTrees._mergeRelativePath (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/index.js:238:31)
    at BroccoliMergeTrees.build (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/index.js:50:24)
    at /Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin/read_compat.js:61:34
    at lib$rsvp$$internal$$tryCatch (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin/node_modules/promise-map-series/node_modules/rsvp/dist/rsvp.js:1036:16)
    at lib$rsvp$$internal$$invokeCallback (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin/node_modules/promise-map-series/node_modules/rsvp/dist/rsvp.js:1048:17)
    at lib$rsvp$$internal$$publish (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin/node_modules/promise-map-series/node_modules/rsvp/dist/rsvp.js:1019:11)
    at lib$rsvp$asap$$flush (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin/node_modules/promise-map-series/node_modules/rsvp/dist/rsvp.js:1198:9)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)

The broccoli plugin was instantiated at:
    at BroccoliMergeTrees.Plugin (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin/index.js:7:31)
    at new BroccoliMergeTrees (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/index.js:29:10)
    at ModulesPreprocessor.inputTreeWithStyles (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/lib/modules-preprocessor.js:62:10)
    at ModulesPreprocessor.toTree (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-css-modules/lib/modules-preprocessor.js:34:30)
    at /Users/my-user/Code/hidden-files-css-modules/node_modules/ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors.js:184:26
    at Array.forEach (native)
    at processPlugins (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors.js:182:11)
    at module.exports.preprocessJs (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors.js:175:10)
    at EmberApp.appAndDependencies (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-cli/lib/broccoli/ember-app.js:1044:25)
    at EmberApp.javascript (/Users/my-user/Code/hidden-files-css-modules/node_modules/ember-cli/lib/broccoli/ember-app.js:1159:34)

`ember test` fails with error in addon

ember-cli: 2.12.0
ember-source: 2.12.0
ember-css-modules: 0.6.5

Created a new addon via ember addon, added an addon/styles directory with a .placeholder file inside and I get this error when I run ember test:

Error: Unable to provide the modules tree before the preprocessor has been invoked
    at ModulesPreprocessor.getModulesTree (/Users/devers/Projects/test-engine/node_modules/ember-css-modules/lib/modules-preprocessor.js:21:11)
    at Class.getModulesTree (/Users/devers/Projects/test-engine/node_modules/ember-css-modules/index.js:78:37)
    at OutputStylesPreprocessor.dynamicHeaderConcat (/Users/devers/Projects/test-engine/node_modules/ember-css-modules/lib/output-styles-preprocessor.js:42:32)
    at OutputStylesPreprocessor.toTree (/Users/devers/Projects/test-engine/node_modules/ember-css-modules/lib/output-styles-preprocessor.js:27:21)
    at /Users/devers/Projects/test-engine/node_modules/ember-cli-preprocess-registry/preprocessors.js:180:26
    at Array.forEach (native)
    at processPlugins (/Users/devers/Projects/test-engine/node_modules/ember-cli-preprocess-registry/preprocessors.js:178:11)
    at module.exports.preprocessCss (/Users/devers/Projects/test-engine/node_modules/ember-cli-preprocess-registry/preprocessors.js:148:10)
    at Class.compileStyles (/Users/devers/Projects/test-engine/node_modules/ember-cli/lib/models/addon.js:788:33)
    at Class.treeForAddon (/Users/devers/Projects/test-engine/node_modules/ember-cli/lib/models/addon.js:662:27)
    at Class._treeFor (/Users/devers/Projects/test-engine/node_modules/ember-cli/lib/models/addon.js:517:33)
    at Class.treeFor (/Users/devers/Projects/test-engine/node_modules/ember-cli/lib/models/addon.js:477:21)
    at project.addons.map.addon (/Users/devers/Projects/test-engine/node_modules/ember-cli/lib/broccoli/ember-app.js:525:20)
    at Array.map (native)
    at EmberAddon.EmberApp.addonTreesFor (/Users/devers/Projects/test-engine/node_modules/ember-cli/lib/broccoli/ember-app.js:523:30)
    at EmberAddon._addonTree (/Users/devers/Projects/test-engine/node_modules/ember-cli/lib/broccoli/ember-app.js:921:36)

addon I've tested this in here: https://github.com/deverstalmage/test-engine

Subclassing support?

Unsure if this is a thing that goes against CSS Modules. But in case it's a bug. Would you expect subclassing to work?

/* thing/components/my-component/component.js */

export Ember.Component.extend({
  classNameBindings: ['styles.component'],
  foo: 'bar'
});
/* thing/components/some-component/component.js */

import MyComponent from 'thing/components/my-component/component';

export MyComponent.extend({
  foo: 'beep'
});

If subclassing were supported I'd expect to get all the styles from MyComponent in SomeComponent.

Invalid imports from virtual modules halt the build with an unhelpful error

In one of our addon's index.js:

module.exports = {
  options: {
    cssModules: {
      // ...
      virtualModules: {
        'ui-colors': {
          'ui-white': '#fff',
          // ...
        }
      }
    }
  }
}

and in one of .css file:

@value ui-white from 'ui-colors';

This works on ember-css-modules v0.5.x, but after I upgrade to v0.6.2, resolve this import from virtualModules will throw an error:

The Broccoli Plugin: [CSSModules] failed with:
TypeError: Cannot read property 'root' of undefined
    at resolveExternalPath (/Users/nightire/Code/ui.cform.io/node_modules/ember-css-modules/lib/resolve-path.js:45:38)
    at ModulesPreprocessor.resolvePath [as _resolvePath] (/Users/nightire/Code/ui.cform.io/node_modules/ember-css-modules/lib/resolve-path.js:15:12)
    at ModulesPreprocessor.resolvePath (/Users/nightire/Code/ui.cform.io/node_modules/ember-css-modules/lib/modules-preprocessor.js:165:15)
    at ModulesPreprocessor.onImportResolutionFailure (/Users/nightire/Code/ui.cform.io/node_modules/ember-css-modules/lib/modules-preprocessor.js:128:27)
    at /Users/nightire/Code/ui.cform.io/node_modules/broccoli-css-modules/lib/link-modules.js:47:19
    at Rule.each (/Users/nightire/Code/ui.cform.io/node_modules/postcss/lib/container.js:114:22)
    at /Users/nightire/Code/ui.cform.io/node_modules/broccoli-css-modules/lib/link-modules.js:42:10
    at tryCatch (/Users/nightire/Code/ui.cform.io/node_modules/rsvp/dist/rsvp.js:538:12)
    at invokeCallback (/Users/nightire/Code/ui.cform.io/node_modules/rsvp/dist/rsvp.js:553:13)
    at /Users/nightire/Code/ui.cform.io/node_modules/rsvp/dist/rsvp.js:628:16
    at flush (/Users/nightire/Code/ui.cform.io/node_modules/rsvp/dist/rsvp.js:2373:5)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)

The broccoli plugin was instantiated at:
    at CSSModules.Plugin (/Users/nightire/Code/ui.cform.io/node_modules/broccoli-caching-writer/node_modules/broccoli-plugin/index.js:10:31)
    at CSSModules.CachingWriter [as constructor] (/Users/nightire/Code/ui.cform.io/node_modules/broccoli-caching-writer/index.js:18:10)
    at new CSSModules (/Users/nightire/Code/ui.cform.io/node_modules/broccoli-css-modules/index.js:26:10)
    at CSSModules (/Users/nightire/Code/ui.cform.io/node_modules/broccoli-css-modules/index.js:24:47)
    at ModulesPreprocessor.toTree (/Users/nightire/Code/ui.cform.io/node_modules/ember-css-modules/lib/modules-preprocessor.js:38:53)
    at /Users/nightire/Code/ui.cform.io/node_modules/ember-cli-preprocess-registry/preprocessors.js:180:26
    at Array.forEach (native)
    at processPlugins (/Users/nightire/Code/ui.cform.io/node_modules/ember-cli-preprocess-registry/preprocessors.js:178:11)
    at Function.module.exports.preprocessJs (/Users/nightire/Code/ui.cform.io/node_modules/ember-cli-preprocess-registry/preprocessors.js:171:10)
    at Class.preprocessJs (/Users/nightire/Code/ui.cform.io/node_modules/ember-cli/lib/models/addon.js:814:25)
    at Class.processedAddonJsFiles (/Users/nightire/Code/ui.cform.io/node_modules/ember-cli/lib/models/addon.js:826:17)
    at Class.compileAddon (/Users/nightire/Code/ui.cform.io/node_modules/ember-cli/lib/models/addon.js:742:24)
    at Class.treeForAddon (/Users/nightire/Code/ui.cform.io/node_modules/ember-cli/lib/models/addon.js:514:26)
    at Class._treeFor (/Users/nightire/Code/ui.cform.io/node_modules/ember-cli/lib/models/addon.js:371:33)
    at Class.treeFor (/Users/nightire/Code/ui.cform.io/node_modules/ember-cli/lib/models/addon.js:339:21)
    at /Users/nightire/Code/ui.cform.io/node_modules/ember-cli/lib/broccoli/ember-app.js:499:20

I was tracking this deeper and found in error has been thrown at https://github.com/salsify/ember-css-modules/blob/master/lib/resolve-path.js#L41 because addonName could not be parsed correctly:

2016-12-11 4 51 23

Composing with localClassNameBindings fails

I have a sample repo here where I try to compose a CSS class from another component and then apply said class conditionally with localClassNameBindings. This results in the error:

Error: Assertion Failed: classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. ['foo', ':bar']

Not working in ember 2.0

In Ember 2.0.3 this line raises an error because owner is a Container instance and doesn't have a register method.

Will try to fix it, but I mention in case I don't have time today and you want to tackle it.

Missing caching strategy

On our ember-cli app we're seeing these deprecations:

DEPRECATION: ember-cli-htmlbars-inline-precompile is opting out of caching due to an AST plugin that does not provide a caching strategy: `ember-css-modules`.
DEPRECATION: ember-cli-htmlbars is opting out of caching due to an AST plugin that does not provide a caching strategy: `ember-css-modules`.

I don't quite understand what's going on. In ember-cli/ember-cli-htmlbars#92 I was asked to file an issue here.

Strategy for importing legacy files

I'm trying to finally move Canvas over to ember-css-modules. My initial plan was to basically set it up so that the diff before and after the use of ember-css-modules would be 0 and then slowly start pulling things into the component pods with โœจ prefixes.

We have quite a few stylesheets with basic utility classes. What's your approach to skip the rewriting of classes for those files? I tried @after-module but that just guarantees load order.

Seems to mess up addon assets

I have a dependency on headroom.js, in my addon, and it can no longer find it, seems to have undefined in the path.

The Broccoli Plugin: [SourceMapConcat: Concat: Vendor /assets/vendor.js] failed with:
Error: ENOENT: no such file or directory, stat '/Users/rwwagner/shipshape/ember-3d-nav/tmp/source_map_concat-input_base_path-KLVmmqhC.tmp/0/undefined/headroom.js/dist/headroom.min.js'

Incompatible with ember-cli-sass

I've posted this issue in ember-cli-sass too, I can't figure out what the problem is, just know that the two addons don't work together.

Error: File not found: /app/styles/app.scss
in any of the following include paths:

A fresh app with latest ember-cli-sass works fine. When ember-css-modules is installed the above error occurs. Would be nice to have both play well with each other.

Usage within add-on causing error

I'm encountering an issue when trying to convert an existing add-on I maintain to use this add-on. I've updated the index.js to include the options object, but error occurs because of a pre-existing function that imports dependencies into the consuming app.

Guilty file (index.js) is viewable here.

Cannot read property 'plugins' of undefined TypeError: Cannot read property 'plugins' of undefined at Class.module.exports.getPlugins (/Users/J/git/ember-cli-notifications/node_modules/ember-css-modules/index.js:48:24) at ModulesPreprocessor.getPlugins (/Users/J/git/ember-cli-notifications/node_modules/ember-css-modules/lib/modules-preprocessor.js:87:30) at ModulesPreprocessor.toTree (/Users/J/git/ember-cli-notifications/node_modules/ember-css-modules/lib/modules-preprocessor.js:43:19) at /Users/J/git/ember-cli-notifications/node_modules/ember-cli-preprocess-registry/preprocessors.js:184:26 at Array.forEach (native) at processPlugins (/Users/J/git/ember-cli-notifications/node_modules/ember-cli-preprocess-registry/preprocessors.js:182:11) at Function.module.exports.preprocessJs (/Users/J/git/ember-cli-notifications/node_modules/ember-cli-preprocess-registry/preprocessors.js:175:10) at Class.Addon.preprocessJs (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/models/addon.js:724:23) at Class.Addon.processedAddonJsFiles (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/models/addon.js:736:15) at Class.Addon.compileAddon (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/models/addon.js:652:22) at Class.Addon.treeForAddon (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/models/addon.js:403:24) at Class._treeFor (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/models/addon.js:322:31) at Class.treeFor (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/models/addon.js:290:19) at /Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/broccoli/ember-app.js:463:20 at Array.map (native) at EmberAddon.EmberApp.addonTreesFor (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/broccoli/ember-app.js:461:30) at EmberAddon._addonTree (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/broccoli/ember-app.js:871:36) at EmberAddon.EmberApp._processedVendorTree (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/broccoli/ember-app.js:916:20) at EmberAddon.EmberApp._processedExternalTree (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/broccoli/ember-app.js:947:21) at EmberAddon.EmberApp.appAndDependencies (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/broccoli/ember-app.js:1043:30) at EmberAddon.EmberApp.javascript (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/broccoli/ember-app.js:1159:34) at EmberAddon.EmberApp.toArray (/Users/J/git/ember-cli-notifications/node_modules/ember-cli/lib/broccoli/ember-app.js:1564:10)

Files processed more than once

I'm noticing that some of our CSS files are being run through PostCSS more than once. I'm not sure if it's an issue at this level or at the broccoli-css-modules level, but a particular plugin that warns about missing retina images fires multiple times for this one file:

screen shot 2017-01-20 at 5 52 49 pm

If it weren't for the noisy warning, I wouldn't have noticed.

I dug in a bit to see if the issue was with the postcss plugin (it's one that I wrote) and as far as I can tell, it's not an issue with the plugin; a debugger set to break when that particular file is first loaded up catches 5 separate times, indicating to me that postcss is processing the file 5 times.

What's interesting is that the same plugin warns for other files, but only once. I have no great way of knowing how many files are processed multiple times, since it just happens to be that a warning is generated here that's easy to see.

Build fails when add styles.css to existing component

When I create new component, like ember g component cc-component, and then add styles.css to component folder build fails and I has this message:
The Broccoli Plugin: [BroccoliMergeTrees] failed with: Error: EEXIST: file already exists, symlink '/Users/bponomarenko/Desktop/css-modules-app/app/components/uu-ii/component.js' -> '/Users/bponomarenko/Desktop/css-modules-app/tmp/broccoli_merge_trees-output_path-L5fMoPvn.tmp/css-modules-app/components/uu-ii/component.js' at Error (native) at Object.fs.symlinkSync (fs.js:1054:18) at symlink (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/symlink-or-copy/index.js:79:14) at symlinkOrCopySync (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/symlink-or-copy/index.js:55:5) at BroccoliMergeTrees.<anonymous> (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/index.js:137:16) at Array.forEach (native) at BroccoliMergeTrees._applyPatch (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/index.js:114:9) at BroccoliMergeTrees.build (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/index.js:101:10) at /Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin/read_compat.js:61:34 at lib$rsvp$$internal$$tryCatch (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin/node_modules/promise-map-series/node_modules/rsvp/dist/rsvp.js:1036:16)

The broccoli plugin was instantiated at: at BroccoliMergeTrees.Plugin (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/node_modules/broccoli-plugin/index.js:7:31) at new BroccoliMergeTrees (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/node_modules/broccoli-merge-trees/index.js:42:10) at ModulesPreprocessor.toTree (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-css-modules/lib/modules-preprocessor.js:50:16) at /Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-cli-preprocess-registry/preprocessors.js:184:26 at Array.forEach (native) at processPlugins (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-cli-preprocess-registry/preprocessors.js:182:11) at module.exports.preprocessJs (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-cli-preprocess-registry/preprocessors.js:175:10) at EmberApp.appAndDependencies (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-cli/lib/broccoli/ember-app.js:1071:25) at EmberApp.javascript (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-cli/lib/broccoli/ember-app.js:1199:34) at EmberApp.toArray (/Users/bponomarenko/Desktop/css-modules-app/node_modules/ember-cli/lib/broccoli/ember-app.js:1604:10)

Option to not automatically localize 3rd party SCSS

Hi there,

Thanks for this really cool and helpfull addon.

I started an Ember app from scratch to understand this addon's behavior better and get used to it.
So far, so good. Currently I'm at the point where I installed ember-power-select. I also figured out how to import those 3rd party SCSS styles globally (ecm-bootstrap) without being automatically localized by ember-css-modules but now I have all the styles for this power-select component in my CSS output:

The global styles are imported via:

// third-party.scss
@import "ember-power-select";

// app.scss
@after-module "./third-party";

which works nice!

But in the CSS output are also styles like:

._ember-power-select_4iaeql {
  position: relative; }

._ember-power-select_4iaeql *, ._ember-power-select-dropdown_4iaeql * {
  box-sizing: border-box; }

._ember-power-select-trigger_4iaeql {
  position: relative;
  border-top: 1px solid #aaaaaa;
  border-bottom: 1px solid #aaaaaa;
  border-right: 1px solid #aaaaaa;
  border-left: 1px solid #aaaaaa;
  border-radius: 4px;
  background-color: #ffffff;
  line-height: 1.75;
  overflow-x: hidden;
  text-overflow: ellipsis;
  min-height: 1.75em;
  user-select: none;
  -webkit-user-select: none;
  color: inherit; }

I think it's because ember-css-modules recognizes a new component (power-selectthrough the ember-power-select addon) and therefore generates styles.

Is there a way to prevent automatically generating localized styles for addon components?
I'm sorry if there's a possibility that I've read over in the docs...

Thanks in advance! =)

Relative paths to files

I'm using 'postcss-inline-svg' and I would like to access svg files that are relative to the style.css in each component:

component/
-- template.hbs
-- component.js
-- styles.css
-- assets/
---- icon.svg

When I tried to access 'assets/icon.svg' in 'styles.css', it can't find it and throws an error:

background-image: svg-load('assets/icon.svg';

Are the paths I can use in the specific component's style.css relative to itself? The plugin is run before css-modules. It doesn't seem to work when '@import'ing a relative file, using 'postcss-import' either.

`cssStyleBindings` Proposal

Hey there!

We've been using this project at @usecanvas and thought we could make it a bit easier to add root component styles based on property truthiness, similar to how classNameBindings works.

What do you think about adding a formal property for this? Here's an example of how cssStyleBindings would work:

export default Ember.Component.extend({
  cssStyleBindings: [
     'component', 'isShowing:is-showing', 'isAvailable:available:unavailable'
  ]
});
<div class="ember-view _component_oksdf _is-showing_lkjsdfl _unavailable_lkjsdf">...</div>

/cc @max

Add Route Controller Styles Example

We should add an example of using styles in route controllers. The README is unclear on this. In reality one needs to import styles into the controller module just like with components.

Addition of contribution guidelines.

I was wanting to contribute to this, but I noticed that there wasn't a formal set of guidelines for contributing. Does anyone want to take the lead on this? I don't mind, but I would most likely just borrow from a well maintained project like erlang/otp.

Deprecation: Don't override `this.options.babel`

DEPRECATION: Ember CLI addons manage their own module transpilation during the `treeForAddon` processing. `ember-css-modules` (found at `/path/to/my/app/node_modules/ember-css-modules`) has overridden the `this.options.babel` options which conflicts with the addons ability to transpile its `addon/` files properly. Falling back to default babel configuration options.

Allow redefining parser, syntax and stringifier PostCSS options

I've managed to make ember-css-modules work with our SASS codebase, however the solution is just one big hack. Would be nice to have a proper way of doing this. Currently css-modules-loader-core doesn't accept most of the options listed here but this should be fixed with css-modules/css-modules-loader-core#59.

And, while I'm here, just wanted to say thanks for the addon โ€” I've been waiting for something similar for ages! ๐Ÿ˜†

Nested Pod Styles

I'm not sure that this supports nested pod components. For example, given the structure

/components
  /infinite-list
    -component.js
    -template.hbs
    -styles.css
    /list-item
      styles.css
      ...

I will receive the error Uncaught Error: Failed to create an instance of 'styles:infinite-list/list-item'. Most likely an improperly defined class or an invalid module export. Am I doing something wrong?

CssSyntaxError processing custom fonts (svg/eot/ttf/woff)

Broccoli dependence fails as soon as a custom font is found:

CssSyntaxError: /PATH/tmp/cssmodules-input_base_path-nX6Fimql.tmp/0/poc-css-modules/styles/fonts/new-fontface.svg:1:1: Unknown word
    at Input.error (/PATH/node_modules/ember-css-modules/node_modules/broccoli-css-modules/node_modules/css-modules-loader-core/node_modules/postcss/lib/input.js:61:21)
...

The broccoli plugin was instantiated at: 
    at CSSModules.Plugin (/PATH/node_modules/ember-css-modules/node_modules/broccoli-css-modules/node_modules/broccoli-caching-writer/node_modules/broccoli-plugin/index.js:10:31)
    at CSSModules.CachingWriter [as constructor] (/PATH/node_modules/ember-css-modules/node_modules/broccoli-css-modules/node_modules/broccoli-caching-writer/index.js:21:10)
    at new CSSModules (/PATH/node_modules/ember-css-modules/node_modules/broccoli-css-modules/index.js:16:10)
    at ModulesPreprocessor.toTree (/PATH/node_modules/ember-css-modules/lib/modules-preprocessor.js:45:22)
    at /PATH/node_modules/ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors.js:184:26
    at Array.forEach (native)
    at processPlugins (/PATH/node_modules/ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors.js:182:11)
    at module.exports.preprocessJs (/PATH/node_modules/ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors.js:175:10)
    at EmberApp.appAndDependencies (/PATH/node_modules/ember-cli/lib/broccoli/ember-app.js:1022:25)
    at EmberApp.javascript (/PATH/node_modules/ember-cli/lib/broccoli/ember-app.js:1137:34)

Style inheritance when extending another component

I am looking to have a base component that other components extend from. The base component would have some local styles in it's styles.css, and then the extended components would also have some of their own local styles.

Is there already a good way to do this?

Right now I am doing something really janky, and having the sub-classed compoents use the composes property:

// /app/features/components/app-card/styles.css

.card {
  composes: card from '../base-card/styles';

  &.app-card {
    .icon {
      .inner-container {
        span {
          display: block;
          width: 100%;
          height: 100%;
          background-size: cover;
        }
      }
    }
  }
}

.icon {
  composes: icon from '../base-card/styles';
}

.inner-container {
  composes: inner-container from '../base-card/styles';
}

.name {
  composes: name from '../base-card/styles';
}
// /app/features/components/base-card/styles.css

.card {
  border: solid 1px rgb(221, 221, 221);
  border-radius: 3px;
  padding: 6px;

  &:hover {
    border-color: rgb(60, 169, 231);

    .name {
      background-color: rgb(190, 217, 231);
    }
  }

  .icon {
    padding-bottom: 100%;
    position: relative;

    .inner-container {
      position: absolute;
      z-index: 100;
      top: 0; left: 0; bottom: 0; right: 0;
    }
  }

  .name {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    background-color: rgb(221, 221, 221);
    padding: 3px;
    height: 70px;

    h4 {
      margin: 0;
    }
  }
}

Integration tests are broken when using ember-css-modules

The following exception gets thrown:

Uncaught Error: Failed to create an instance of 'styles:components/my-component'. Most likely an improperly defined class or an invalid module export.

This is probably caused by the fact that the initializer never gets called. Unit tests are likely broken as well, though I didn't test it.

Addon Issues

I get an Cannot find module error when trying to import my styles into my component in my addon. Example:

import Ember from 'ember';
import layout from './template';
import styles from './styles';

export default Ember.Component.extend({
  layout,
  styles
});

Pod folder structure:

-addon
  -components
    -toggle-switch
      -component.js
      -styles.css
      -template.hbs

I'm not sure what is going on but it looks like styles.css is not being registered as a module in the resolver like template.hbs is.

Dealing with modifiers

Another one for support docs. What's a good pattern to deal with modifiers? For example let's say I have a button:

<my-button destructive=true>Beep Boop</my-button>
<my-button destructive=true primary=true>Beep Boop</my-button>
<my-button size="lg">Beep Boop</my-button>
<my-button plain=true iconButton=true><icon name="cat" /></my-button>
import Ember from 'ember';

export default Ember.Component.extend({
  attributeBindings: ['disabled', 'type'],
  classNameBindings: [
    'styles.my-button',
    'destructive:styles.destructive',
    'iconButton:styles.icon',
    'full:styles.full',
    'plain:styles.plain',
    'primary:styles.primary',
  ],
  tagName: 'button',
  type: 'button',

  click() {
    return this.attrs.action && this.attrs.action();
  },
});

Is the concept of modifiers not really a good pattern for CSS Modules? I'm translating BEM code.

Edit: This doesn't work and is pseudo code.

Need some suggestions related with ember-css-modules

CSS modules is awesome, totally, we really enjoy to write styles with it.

Now we face to some particular requirements, I'm not sure how to do these, so I really need some helps:

  1. For what I understanding, ember-css-modules will process any css files under app/ directory, is there any possible or recommended way to excludes some of them? Because some style files we need to use them for other purposes and we don't need to treat them as css modules.
  2. If no.1 is impossible or not to recommended, how can we split the final stylesheets into two or more individual files? This is a common requirement, like themes.

The best solution that I can imagine is able to put some styles in a specific folder, ember-css-module will ignore it. Then we can use other system (less, sass, or even plain css) to process it and output to one or more individual files. I would like to know the possibilities and also open to other ideas.

I've researched a little and seems like broccoli-funnel can helps us in this situation, but I'm not sure the impact to ember-css-modules, so I think hearing some advices from you first is a better idea, looking forward your suggestions, thank you in advance.

Not cooperating with ember-cli-sass

After installing ember-css-modules I'm receiving the following errors:

The Broccoli Plugin: [SassCompiler] failed with:
Error: File not found: /app/styles/app.scss
in any of the following include paths:
  /repos/transact/tmp/sass_compiler-input_base_path-TXfUoVjg.tmp/0
    at Object.findFileSync (/repos/transact/node_modules/ember-cli-sass/node_modules/broccoli-sass-source-maps/node_modules/include-path-searcher/index.js:12:9)
    at SassCompiler.build (/repos/transact/node_modules/ember-cli-sass/node_modules/broccoli-sass-source-maps/index.js:63:31)
    at /repos/transact/node_modules/ember-cli-sass/node_modules/broccoli-sass-source-maps/node_modules/broccoli-caching-writer/index.js:149:21
    at lib$rsvp$$internal$$tryCatch (/repos/transact/node_modules/rsvp/dist/rsvp.js:1036:16)
    at lib$rsvp$$internal$$invokeCallback (/repos/transact/node_modules/rsvp/dist/rsvp.js:1048:17)
    at lib$rsvp$$internal$$publish (/repos/transact/node_modules/rsvp/dist/rsvp.js:1019:11)
    at lib$rsvp$asap$$flush (/repos/transact/node_modules/rsvp/dist/rsvp.js:1198:9)
    at nextTickCallbackWith0Args (node.js:420:9)
    at process._tickCallback (node.js:349:13)

The broccoli plugin was instantiated at:
    at SassCompiler.Plugin (/repos/transact/node_modules/ember-cli-sass/node_modules/broccoli-sass-source-maps/node_modules/broccoli-caching-writer/node_modules/broccoli-plugin/index.js:7:31)
    at SassCompiler.CachingWriter [as constructor] (/repos/transact/node_modules/ember-cli-sass/node_modules/broccoli-sass-source-maps/node_modules/broccoli-caching-writer/index.js:18:10)
    at new SassCompiler (/repos/transact/node_modules/ember-cli-sass/node_modules/broccoli-sass-source-maps/index.js:20:17)
    at /repos/transact/node_modules/ember-cli-sass/index.js:39:12
    at Array.map (native)
    at SASSPlugin.toTree (/repos/transact/node_modules/ember-cli-sass/index.js:36:34)
    at /repos/transact/node_modules/ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors.js:184:26
    at Array.forEach (native)
    at processPlugins (/repos/transact/node_modules/ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors.js:182:11)
    at module.exports.preprocessCss (/repos/transact/node_modules/ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors.js:152:10)

I'm trying to configure ember-css-modules to work with ember-cli-sass, which appears to be supported, but this error occurs as long as I have both ember-cli-sass and ember-css-modules installed, no matter what cssModules options I try.

I've tried this with ember-cli-sass version 5.3.1 and version 5.6.0, and ember-css-modules 0.5.0.

Any ideas?

Shared custom properties and @values

In our current codebase we @import "basscss"; and then a the bottom of the app.css file have a :root with a bunch of custom properties. Here is an example:

/* my-app/styles/app.css */
@import "basscss";

.some-component {
  margin-bottom: var(--space-1);
}

:root {
  --space-1: 1rem;
}

Setting the custom property will affect both Basscss and the component code. Basscss happens to have a bunch of spacer classes (.mb1, .mb2, etc.) that make use of --space. These classes are great but sometimes it is more idiomatic to write:

<div class="my-component">Hello World</div>

<!-- vs -->

<div class="my-component mb1">Hello World</div>

By being able to use the same custom properties in both our utility libraries and components we get a nice level of consistency. I tried rebuilding this with a contrived use of @value but didn't succeed. Any pointers for this scenario?

Not working with other css tools (Less)

after ember-css-modules is installed ember build fails as ember-cli-less could not find the required files.

The Broccoli Plugin: [LessCompiler] failed with:
Error: File not found: /app/styles/app.less
in any of the following include paths:
  /Users/anton/work/opensight-ember/tmp/less_compiler-input_base_path-UwlBJIdU.tmp/0
    at Object.findFileSync (/Users/anton/work/opensight-ember/node_modules/include-path-searcher/index.js:12:9)
    at LessCompiler.build (/Users/anton/work/opensight-ember/node_modules/broccoli-less-single/index.js:49:35)
    at /Users/anton/work/opensight-ember/node_modules/broccoli-caching-writer/index.js:152:21
    at lib$rsvp$$internal$$tryCatch (/Users/anton/work/opensight-ember/node_modules/rsvp/dist/rsvp.js:493:16)
    at lib$rsvp$$internal$$invokeCallback (/Users/anton/work/opensight-ember/node_modules/rsvp/dist/rsvp.js:505:17)
    at lib$rsvp$$internal$$publish (/Users/anton/work/opensight-ember/node_modules/rsvp/dist/rsvp.js:476:11)
    at lib$rsvp$asap$$flush (/Users/anton/work/opensight-ember/node_modules/rsvp/dist/rsvp.js:1198:9)
    at doNTCallback0 (node.js:417:9)
    at process._tickCallback (node.js:346:13)

The broccoli plugin was instantiated at:
    at LessCompiler.Plugin (/Users/anton/work/opensight-ember/node_modules/broccoli-caching-writer/node_modules/broccoli-plugin/index.js:10:31)
    at LessCompiler.CachingWriter [as constructor] (/Users/anton/work/opensight-ember/node_modules/broccoli-caching-writer/index.js:21:10)
    at new LessCompiler (/Users/anton/work/opensight-ember/node_modules/broccoli-less-single/index.js:21:17)
    at /Users/anton/work/opensight-ember/node_modules/ember-cli-less/index.js:28:12
    at Array.map (native)
    at LESSPlugin.toTree (/Users/anton/work/opensight-ember/node_modules/ember-cli-less/index.js:24:34)
    at /Users/anton/work/opensight-ember/node_modules/ember-cli-preprocess-registry/preprocessors.js:184:26
    at Array.forEach (native)
    at processPlugins (/Users/anton/work/opensight-ember/node_modules/ember-cli-preprocess-registry/preprocessors.js:182:11)
    at module.exports.preprocessCss (/Users/anton/work/opensight-ember/node_modules/ember-cli-preprocess-registry/preprocessors.js:152:10)

I've tried not to use app.less but rather different filename, but still no luck.

I'd like to be able to use both (less and css-modules) at the same time, even if they isolated from each other

Support dynamic values in `local-class`

Currently the preprocessor will reject non-static local-class values, e.g.

{{my-component local-class=(some-kind-of subExpression)}}

There's no technical reason we can't handle this case, but it does raise a couple of interesting questions. The simplest translation of the above would look something like:

{{my-component class=(get styles (some-kind-of subExpression))}}

However, this wouldn't handle cases like this (contrived) example where multiple class names are produced:

{{my-component local-class=(concat 'foo bar')}}

For these cases, we'll probably need to introduce a helper to split the string and look up the appropriate classes, so the compiled version might look something like:

{{my-component class=(lookup-module-styles (unbound styles) (some-kind-of subExpression))}}

postcss-color-function support

Currently it isn't possible to use an imported @value in a PostCSS color function. For example:

@value --light-gray from "things/styles/colors";

.foobar {
  background: color(--light-gray alpha(50%));
}

This results in:

Unable to parse color from string "i__const___light_gray_473"

By comparison this works fine:

@value --light-gray: #999;

.foobar {
  background: color(--light-gray alpha(50%));
}

I also tried moving postcss-color-function to the before hook but then the error message is:

Unable to parse color from string "--light-gray"

Which makes sense given that at that stage it's just a string.

Skip processing chained classes?

How would you feel about the ability to skip chained classes:

.my-component {}

.my-component.is-expanded {}

Turns into

._hjk23_my-component {}

._hjk23_my-component.is-expanded {}

It's a fairly common practice to have state modifiers like that and chaining is encouraged because it increases specificity.

@values with commas and quotes in them?

Is it possible to have a @value for a font-family?

@value --font-family: "Helvetica Neue", Arial, Geneva, sans-serif;

.foobar {
  font-family: --font-family;
}

/* yields */

.foobar {
  font-family: "Helvetica Neue";
}

Allow specifying import order of global styles

It is common to have a set of base styles for a given application. Those base styles often rely on import order. By default ember-cli takes care of this:

In the production build, the @import statements are replaced with the contents of their files and the final minified, concatenated single CSS file is built to dist/assets/yourappname-FINGERPRINT_GOES_HERE.css.

An example in Ember land:

/* app/styles/app.css */

@import "normalize.css";
@import "base.css";
@import "typography.css";
...
@import "utilities.css";

When installing ember-css-modules this no longer works. Instead all files in app/styles/ are concatenated alphabetically โ€“ which removes the ability to specify import order.

Besides basic functionality it would also be fantastic if postcss-import was supported. This allows globbing, importing NPM modules, etc. (in the above example you could imagine normalize.css just being an NPM module vs vendored in).

Unable to use composition with localClassNameBindings array

I'm trying to use the localClassNameBindings array with a single computed property that returns a class that use the composes functionality provided by this add-on. See the basic example below.

classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. ['foo', ':bar']

import Ember from 'ember';

const { Component, computed } = Ember;

export default Component.extend({
  localClassNames: ['stock-indicator'],
  localClassNameBindings: ['outOfStock:stock-indicator--unavailable:stock-indicator--available'],

  outOfStock: computed.equal('stock.availability', 'out-stock'),

});
.stock-indicator {
  composes: white px1 rounded from global;
}

  .stock-indicator--available {
    composes: bg-blue from global;
  }

  .stock-indicator--unavilable {
    composes: bg-red from global;
  }

Introduction to ember-css-modules at Global Ember Meetup

Would someone familiar with the project be interested tell in giving an Introduction to ember-css-modules at Global Ember Meetup on June 11th?

An introduction to <addon> talk answers the following questions:

  1. What problem is this addon looking to solve?
  2. How does a developer get started?
  3. What does a developer need to know to effectively use the addon?

The recording will be edited and we'll create video like this https://vimeo.com/album/3607049 that you can use as an introduction to this addon.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.