[Coldbox 6.1.0][Coldbox-Elixir 3.1.6] Best Practices for SCSS and Image Files

Skip to first unread message

David Levin

Dec 9, 2020, 7:15:38 PM12/9/20
to ColdBox Platform
I'm getting started with Coldbox Elixir and so far it's amazing! I love being able to fire up npm run watch and it will automatically compile my SCSS and refresh the browser via browsersync. However, I'm a little confused as to how I should proceed with using images in my Elixir projects.  

Here's what my folder structure currently looks like (simplified for this example):
     /css/     // compiled/minified css goes here
     /images/  // webpack likes to put images here (sometimes)
     /js/      // compiled/minified js goes here
     /js/      // my raw source javascript files
     /sass/    // my raw source scss files
     /img/     // my original image files

When I place a reference to an image in my scss file like this:
.header {
      background-image: url( '../../static/img/header-gradient.png' ); 

Webpack makes a copy of the image to /includes/images/ and rewrites the rendered css file to point to the proper image.

However, when I make a subsequent change to my scss file, webpack deletes the image in  /includes/images/ during the cleanup process and never re-creates it thus breaking the compiled CSS link.

This behavior makes me think that I might be treating images wrong.  I don't see any reason why a duplicate image file needs to be generated. Is there a way to use the existing images in my /static/img/ folder and have webpack automatically change the image reference when compiling CSS without making a copy of the image?  In other words, it would be great if Webpack would simply find the reference in the SCSS file:
url( '../../static/img/header-gradient.png' ) 
... and change it to
url( '../static/img/header-gradient.png' )   
... so it stays relative to the compiled css file.

The problem I see with making duplicate copies images used in CSS files is that some images will remain in my /static/img/ folder, and any image that is referenced in CSS gets duplicated to /includes/images/.  This behavior feels like it would make keeping images organized more difficult and also wastes space. 

Here is my webpack.config file for reference:
const elixir    = require( "coldbox-elixir" );
const webpack   = require( "webpack" );

    plugins: [
        // globally scoped items which need to be available in all templates
        new webpack.ProvidePlugin({
            $              : "jquery",
            jQuery         : "jquery",
            "window.jQuery": "jquery",
            "window.$"     : "jquery",
            "Vue"          : ["vue/dist/vue.esm.js", "default"],
            "window.Vue"   : ["vue/dist/vue.esm.js", "default"]
    devtool: "source-map"

 | Elixir Asset Management
 | Elixir provides a clean, fluent API for defining some basic Gulp tasks
 | for your ColdBox application. By default, we are compiling the Sass
 | file for our application, as well as publishing vendor resources.

module.exports = elixir( mix => {

        proxy: "localhost:62351",
        notify: false
    // Mix App styles
                name: "app",
                entryDirectory: "resources/js/"
                name: "app",
                entryDirectory: "resources/sass/"
                name : "vendor.min",
                entryDirectory : ""

} );

Jon Clausen

Dec 10, 2020, 8:52:23 AM12/10/20
to col...@googlegroups.com



The reason this is done is because of a couple off factors:

1. The `/resources/assets` directory is typically removed from production packages

2. The relative paths to the `/resources` version of the image may be outside of the webroot, depending on the pack and the way you have it configured.

That said, I’ve never experienced the issue you are describing with CSS assets disappearing and then not being re-copied on a change, and I use Elixir day in/out. This may be a bug, or it may be a configuration issue with the relative paths. You may want to report that as an issue on the Github repo.

You  have another option, as well, which is to normalize any images referenced in your CSS file in as base64 ( you can also do this with fonts ).  You can see this in the Relax repo - https://github.com/coldbox-modules/relax/blob/development/webpack.config.js#L19 – where any font or image under 100000 bytes is automatically normalized as base64 in to the CSS file. 

That’s not always ideal and makes your CSS much bigger, depending on how many images you use, but it is an option.




You received this message because you are subscribed to the Google Groups "ColdBox Platform" group.
For News, visit http://blog.coldbox.org
For Documentation, visit http://wiki.coldbox.org
For Bug Reports, visit https://ortussolutions.atlassian.net/browse/COLDBOX
You received this message because you are subscribed to the Google Groups "ColdBox Platform" group.
To unsubscribe from this group and stop receiving emails from it, send an email to coldbox+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/coldbox/e52a7997-e9c5-40f1-a288-0b6d746a041cn%40googlegroups.com.

David Levin

Dec 10, 2020, 7:00:01 PM12/10/20
to ColdBox Platform
Jon, thank you! Your input was very helpful.  I can see I still have a lot to learn in regards to structuring my app with Elixir. I hadn't considered keeping the `resources/assets` directory out of the production environment.  I've been having a hard time understanding the Coldbox Elixir documentation so I've been looking at the Laraval docs to try and gain insight.  One such page (https://laravel.com/docs/8.x/mix#url-processing) gave me an idea that I've put into place until I can better understand how to use Elixir in my workflow.  

What I did to temporarily address the image issue was to add a slash "/" at the beginning of each URL() statement in my scss files.  This tells Webpack to ignore those files and it won't duplicate them in the /includes/images/ folder.  For example:
background-image: URL( './static/img/my-image.png' );
background-image: URL( '/static/img/my-image.png' ); 
The only downside I see is that you have to always make your URLs absolute from the webroot.

Now I'm currently struggling with how to bring in page-specific .js files. I realized I can't include them like I would have expected like this because none of the dependencies are available (I suspect due to runtime.js).

<!--- Javascript (webpack generated) --->
<script src="#html.elixirPath( "js/runtime.js" )#"></script>
<script src="#html.elixirPath( "js/vendor.js" )#"></script>
<script src="#html.elixirPath( "js/vendor.min.js" )#"></script>
<script src="#html.elixirPath( "js/app.js" )#"></script>

<!--- Page Specific Javascript --->
<script src="./static/js/my-page.js"></script>  // won't work!  Even though jquery is in my vendor.js file, it won't be available for some reason.

Do you happen to know any public repos or examples of code that use Elixir in a best-practices way that allows for different .js files for pages that need them?  The docs don't seem to cover it, and I don't see anything on cfcasts either.  I could probably figure it out if I had access to some working example code to sift through.

Reply all
Reply to author
0 new messages