3
votes

I am very new to Aurelia, and new web development in general (nodejs, gulp, and so on).

Thanks to the Aurelia CLI it was easy for me to setup a nice Aurelia project for Visual Studio Code using Typescript + SASS. I thought it would be a good idea (but please tell me if it is not a good idea :) to use scoped css. There is already much information about this subject, but it is hard to find something that I can actually use. So I thought I would do it myself in the following way:

  1. I have general stylesheets that can be imported "anywhere". Nothing new needs to be done to do this.
  2. There will be component specific stylesheets that match the component name + ".scss". So e.g. if there is a view + model like: component.ts, component.html, there can be a component.scss which will contain styling that is specific for component.ts and component.html and thus should be scoped to this component.

I've tried to use style scoped html tags but this is not widely supported by browsers (and seems to be dropped from the spec?) and I've tried something (I forgot what I've tried exactly) as described on

https://github.com/bryanrsmith/aurelia-binding-loader

with:

<template>
  <require from="styles.css!module!bind" as="styles"></require>

  <div class.one-time="styles.first">First</div>
  <div class.one-time="styles.second">Second</div>
</template>

which was very slow.

My knowledge about all this is very limited and I think it does a conversion from CSS to a JS object, after which the class of a tag are bound to the style in the JS object.

I thought it would make sense to to this conversion to JS at build time. So with my very limited gulp knowledge I changed process-css.ts in the following way:

import * as gulp from 'gulp';
import * as sourcemaps from 'gulp-sourcemaps';
import * as sass from 'gulp-sass';
import * as project from '../aurelia.json';
import { build } from 'aurelia-cli';
import * as path from "path";
import * as fs from "fs";
import * as rename from "gulp-rename";
import * as postcssmodules from "postcss-modules";
import * as postcss from "postcss"
import * as postcssJs from "postcss-js"
import * as tap from "gulp-tap";

export default function processCSS() {
  return gulp.src(project.cssProcessor.source)
    .pipe(sourcemaps.init())
    .pipe(sass().on('error', sass.logError))
    .pipe(tap(handleCss))
    .pipe(build.bundle())
};

function handleCss(cssFile, t) {
  // get the path of the html file
  var baseFilename = path.basename(cssFile.path, '.css');
  var baseFilepath = path.join(path.dirname(cssFile.path), baseFilename);
  var htmlFilepath = baseFilepath + '.html';

  // check if the html file exists
  if (fs.existsSync(htmlFilepath)) {
    var root = postcss.parse(cssFile.contents.toString());
    var cssAsJson = postcssJs.objectify(root);
    var s = JSON.stringify(cssAsJson);
    cssFile.contents = Buffer.from(s);
  }
}

(adding handleCss).

This is not yet finished. The new object with the style has to be added to the bundle under the same name but WITH an extension ".js". How can I do this in a nice way?

It would be nice if this would work, but still it would be limited to scoped css classes, not css elements. Another possibility I thought about is, maybe the component.scss styling can be inserted into the component.html (e.g. setting style properties of elements) during build time? If so, how could/should this be done? And are there any drawbacks from doing this?

Sorry if there are "dumb" questions in this post, basically this is all very new and it is difficult to find where to begin.

Thanks!

1
I'm not an expert here so I'm just commenting to avoid the "blind leading the blind". But... it's my understanding that Aurelia doesn't do scoped CSS, so whatever solution you plan to do will need to be some sort of hack, or simply naming conventions. If I were you, I'd use SASS and wrap the whole CSS in a class with the name of the component and perhaps a css_ prefix, and add that class to your template tag (<template class='css_user_list>). That should effectively restrict the CSS tags to anything inside that component (and its children). - LStarky
Yup, I agree with Starky, just use the same name as the component for your class (ie .my-component) and because there can't be two components with the same name, you'll never have two classes with the same names either. Optionally, you could actually use an id instead. Arguably that's exactly what it's for (uniquely styling a single element and its descendants). - powerbuoy
Hello thanks both :) What I was planning to do is indeed a bit of a hack. I wanted to do something at build time that at least automates the conversion from the CSS styles to a JS object that could be bound to the elements in the component. Another way could have been to merge the styles into the html elements when building. The solution you two propose might actually be far good enough also. I thought about it also, but didn't think about it enough. Will try it and see how it goes. Thanks again. - Robbert
Just want to mention that aurelia-ux provides scoped css. It is in early alpha, but this feature already exists and I've played around with it a bit. You may want to check it out as a possible solution. - Jeff G
Chiming in here. Scoped CSS has also been dropped from the official specification for the moment as well. - Dwayne Charrington

1 Answers

0
votes

If you're using Aurelia with Webpack, you can use the ConventionDependenciesPlugin so that css/scss files are automatically included just like js and html. Once configured, you no longer need to require the stylesheets. Do note that you may have to restart Webpack watch if you add css/scss file after the html and js files, because ConventionDependenciesPlugin sometimes does not pick up the dependent file.