Mejor forma de aplicar css-modules a AngularJS

Estoy usando css-modules con componentes AngularJS 1.5 ahora. La stack es webpack + css-loader?modules=true webpack css-loader?modules=true + angular 1.5 components + pug .

Actualmente tengo que hacer los siguientes pasos para usar modules css en mi plantilla de pug.

 // my-component.js import template from 'my-component.pug'; import styles from 'my-component.css'; class MyComponent { constructor($element) { $element.addClass('myComponent'); // ------ (1) this.styles = styles; // ------ (2) } } angular.module(name, deps) .component('my-component', { controller: MyComponent, template: template, }); // my-component.pug div(class={{ ::$ctrl.styles.fooBar }}) FooBar // ----- (3) // my-component.css .myComponent { background: green; } .fooBar { color: networking; } 

Hay dos problemas:

  1. Cada componente tiene que inyectar $element y establecer su nombre de class manualmente. La razón para hacer esto es que la label de componente AngularJS existe en el resultado HTML sin classs, lo que hace que CSS sea difícil. Por ejemplo, si uso MyComponent arriba de esta manera:

     <div> <my-component></my-component> </div> 

    generará el siguiente HTML:

     <div> <my-component> <div class="my-component__fooBar__3B2xz">FooBar</div> </my-component> </div> 

    Comparado con ReactJS, <my-component> en el resultado anterior HTML es un extra, a veces hace que CSS sea difícil de escribir. Entonces mi solución es (1) agregarle una class.

  2. La class en la plantilla es demasiado larga (3). Sé que es la forma correcta de hacer reference a $ctrl.styles.fooBar pero esto es demasiado largo.

Mi solución ideal sería así:

 // my-component.js angular.module(name, deps) .component('my-component', { controller: MyComponent, template: template, styles: styles, }); // my-component.css div(css-class="fooBar") FooBar 

La idea es:

  1. make angular.module().component admite un atributo de styles adicional, que automáticamente hará (2) this.styles = styles; en el controller, y aplicar (1) $element.addClass() también.
  2. directiva css-class para aplicar $ctrl.styles al elemento.

Mi pregunta es: no tengo idea de cómo implementar la idea 1 anterior (2 es fácil). Aprecio si alguien pudiera compartir algo de luz sobre esto.

Encontré una solución con la que no estoy satisfecho.

El componente angular puede aceptar una function como plantilla e inyectar con $element . doc

Si la plantilla es una function, se inyecta con los siguientes locales:

  • $ elemento – Elemento actual
  • $ attrs – Objeto de attributes actuales para el elemento

Por lo tanto, podríamos adjuntar la class principal para el componente ( .myComponent ) en la function de plantilla, luego regex replaceá todos los nombres de class con nombres de class comstackdos.

 // utils.js function decorateTemplate(template, styles, className) { return ['$element', $element => { $element.addClass(styles[className]); return template.replace(/\$\{(\w+)\}/g, (match, p1) => styles[p1]); }]; } // my-component.js import style from './my-component.css'; import template from './my-component.pug'; import { decorateTemplate } from 'shanetworking/utils'; class MyComponent { // NO NEED to inject $element in constructor // constructor($element) { ... } angular.module(name, deps) .component('myComponent', { // decorate the template with styles template: decorateTemplate(template, styles, 'myComponent'), }); // my-component.pug, with special '${className}' notation div(class="${fooBar}") FooBar 

Todavía hay un lugar para mejorar que decorateTemplate utiliza el reemploop de expresiones regulares y la plantilla tiene que usar una notación especial ${className} para especificar los nombres de class de los modules css.

Cualquier sugerencia es bienvenida.

ACTUALIZAR

Actualicé mi function decorateTemplate() para aprovechar las características de pug, de modo que los nombres de classs locales puedan escribirse como ._localClassName .

 // utils.js function decorateTemplate(template, styles, className) { return ['$element', ($element) => { $element.addClass(styles[className]); return template.replace(/\sclass="(.+?)"/g, (match, p1) => { let classes = p1.split(/\s+/); classes = classes.map(className => { if (className.startsWith('_')) { let localClassName = className.slice(1); if (styles[localClassName]) { return styles[localClassName]; } else { console.warn(`Warning: local class name ${className} not found`); return className; } } else { return className; } }); return ' class="' + classes.join(' ') + '"'; }); }]; } // my-component.pug ._fooBar FooBar 

Aunque esto es mucho más fácil, no elimina la notación extravagante (comience con _ para los nombres de las classs locales) y regex replace.

Cualquier sugerencia es bienvenida.