0

I'm trying to find best way to support theme styling in my angular 4 app. I'm using SASS variables and theme setup relies on 4 SASS vars: primary and secondary colour, background-image and switch for dark/light theme.

Now, I want to change theme dynamically from the app. I have this for now:

I'm using sass-vars-loader library (https://github.com/epegzz/sass-vars-loader), and load sass variables from JSON file into my _vars.scss during app build. And when I change those vars from the component I write new values to JSON file and trigger app recompile as I'm watching for changes on that file.

This is succesfuly recompiling and loading new variables into _vars.scss during the development, but my question is how can I support that in the production.

To be able to configure webpack, I ejected webpack.config.js with $ng eject thus not using angular-cli commands anymore.

// webpack.config.js

...

{
    "test": /\.scss$|\.sass$/,
    "use": [
      "style-loader",
      {
        "loader": "css-loader",
        "options": {
          "sourceMap": false,
          "importLoaders": 1
        }
      },
      {
        "loader": "postcss-loader",
        "options": {
          "ident": "postcss",
          "plugins": postcssPlugins
        }
      },
      {
        "loader": "sass-loader",
        "options": {
          "sourceMap": false,
          "precision": 8,
          "includePaths": []
        }
      },
      // Reads Sass vars from JSON
      { loader: "@epegzz/sass-vars-loader", options: {
        files: [
          path.resolve(__dirname, 'src/theme.json')
        ]
      }
    }
    ]
  },

... 

"devServer": {
setup: function(app) {
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({
    extended: true
  }));

  app.post("/theme", function(req, res) {
    var payload = req.body,
        theme;

    fs.writeFileSync('src/theme.json', JSON.stringify(payload, null, 3));
    res.send("Success");
  });
},
}

I suppose I need to create custom node.js server which will serve my app and watch for changes, jsut like the webpack-dev-server is doing during development.

Any help is appreciated, Thanks.

lginq
  • 3
  • 2
  • There's no need to do all that with webpack. Take a look there: https://stackoverflow.com/a/40612500/2398593 – maxime1992 Dec 12 '17 at 08:07
  • @Maxime I'm using sass variables across all application, theme vars are dynamic and can be any colour. I need a way to insert user selected values into my _vars.scss, after the app is already compiled. The solution you provide would require to check class on root component and do that in every child component using sass vars. – lginq Dec 13 '17 at 09:13
  • Not on every child component, that's the point – maxime1992 Dec 13 '17 at 09:54
  • Yes you are right, but that still doesn't answer my question. As I need to allow user to choose primary and secondary colour and a background image along with theme dark/light. @Maxime – lginq Dec 13 '17 at 11:11

1 Answers1

0

I suggest you re-think your strategy of using build tools, but I'm not convinced you need to build a server to achieve the result you want.

Maybe you can compile all of the themes, and 'swap' them out at run-time. Replacing css file on the fly (and apply the new style to the page)

If the themes are not fixed, i.e. you can have any combination, the maybe you can embed the 'theme' css in the main html page and swap out those values as required. Change CSS rule at runtime

--- edit ---

I fully understand that it's intimidating to have to do a major design change at this point in your applications lifecycle but I am very certain that your current approach is going to cause you signifigantly more headache.

Angular, SCSS, node etc were not intended for and do not lend themselves to the scenario which you are describing.

Are you aware that in the scenario you're describing; if any user triggers a 'theme change', the website will be 'taken offline' while it's recompiling and that the resulting css theme applied would be visible to everyone using the site, not just the user who triggered it?

Also, the browser isn't using your scss files, it's using the compiled output from all your SCSS files which I believe in ng4's case, is a JS file with the CSS embedded.

In order to do what you're proposing wihtout recompiling angular, (which will require a lot of additional back-end server work and potentially lead to more complexity/reliability issues) you will need to get and populate your vars.SCSS file, combine it with all the other SCSS files, somehow replicate how angular CLI generates the CSS embedded JS file and then load that into your browser, replacing the initial one... and you would need to do all of that from javascript/typescript running in the browser.

Redesign your app a little, create a css 'overlay' file, and at runtime, swap out the values and load it into the DOM to change themes. I'm sure others will weigh in here too, but I believe that's a much better direction to proceed to get the results you want, as quickly as possible.

Liam Fleming
  • 1,016
  • 12
  • 17
  • I need to use this kind of build as the app is already too big and other way will require major change in app design and style. Can't embed to index.html as values are dynamic and won't be available until user select new values and submits. The idea was to read vars from file, insert them into vars.scss and after choosing new values trigger the app to recompile with new values. @Liam Flemming – lginq Dec 13 '17 at 11:16