Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use [hash:base64:5] in JavaScript / TypeScript file

I am using CSS Modules in an Angular Project with Webpack. I had already transformed the class names in .css and .scss files with postcss-modules.

Then with posthtml-css-modules I had changed the values on the class property in html elements for his hash value defined by postcss-modules.

I can say that everything is working fine 💪.

Now, I have a new challenge to resolve.

Angular, has a feature that allows you to change dynamically the value of class in a html element depending on a condition:

https://angular.io/api/common/NgClass

For Example, I can do:

<div [className]="myVar ? 'myClass1' : 'myClass2' " >

If myVar = true, the html element will be:

<div class="myClass1" >

And if myVar = false, the html element will be:

<div class="myClass2" >

Like I do not know what is going to be the value of myVar during compilation time (because the value of myVar depends on user actions) I am not able to set the value for <div css-module="myClass1" > or <div css-module="myClass2" > in order to hash the class names of myClass1 or myClass2.

BUT (Here comes my solution)...

If I can invoke the same function that does [hash:base64:5] (https://github.com/css-modules/postcss-modules#generating-scoped-names)

I can create a function that receives a string as parameter and return the class name as a hash.

It would be something like this:

<div [className]="setMyClassNameInHash(myVar)">

Then in javascript:

function setMyClassNameInHash(condition) {
      return  condition ? doHash64('myClass1') : doHash64('myClass1');
}

doHash64() would be the function that takes a string and returns the hash using [hash:base64:5].

In conclusion, my question is:

¿How I can invoke the same function that does [hash:base64:5] in a javascript file?

Thanks!!!!

like image 872
German Quinteros Avatar asked Mar 03 '20 17:03

German Quinteros


1 Answers

You'll need to integrate a templating step into your build process. The plugin exports the class names and their mapped names to a json file, so you can look up the hashed class name from the original.

Edit: Since the built in templating only works for a single class name and doesn't appear to support replacing class names in things like angular attributes, you could do the templating yourself using a templating library like lodash. If you're already using grunt or gulp, I'd recommend using their template tasks instead of this manual way because they do a lot of things for you, like supporting multiple files.

In your html, you would use lodash delimiters to get the hashed class name like:

<div [className]="myVar
     ? '<%= getHashedClass('myClass1') %>'
     : '<%= getHashedClass('myClass2') %>' " >

Your node build script might look like this:

var fs = require('fs');

postcss([
  require("postcss-modules")({
    // Callback to get hashed class names
    getJSON: function(cssFileName, classNames, outputFileName) {
      var filePath = '/path/to/outputDir/file.html';

      // Function to lookup hashed class names
      var getHashedClass = function(unhashedClass) {
        return classNames[unhashedClass];
      }

      // Read your html file as a string
      var html = fs.readFileSync(path),

      // Use lodash to template it, passing the class lookup function
      var compiled = _.template(html);
      var templated = compiled({
        getHashedClass: getHashedClass
      });

      // Write the templated html
      fs.writeFileSync(path, templated);
    }
  })
]);
like image 63
frodo2975 Avatar answered Nov 15 '22 00:11

frodo2975