Concatenate different sass files to corresponding css files - brunch

In my app/styles/ directory I have the following files
application_blue.scss
application_red.scss
I'd like to concatenate those files into public/stylesheets/application_blue.css and public/stylesheets/application_red.css respectively

stylesheets:
defaultExtension: 'scss'
joinTo:
'stylesheets/application_blue.css': /^app\/styles\/application_blue/
'stylesheets/application_red.css': /^app\/styles\/application_red/
Okay I found the solution, might help others

Related

UnCSS setup with Brunch

Using Brunch as my build-tool for a front-end prototype, I am having difficulty setting up the UnCSS-plugin. I installed the Bootstrap 4-skeleton for a quick setup, and apart from UnCSS everything is running smoothly.
The error I get on brunch build --production is error: UnCSS: no stylesheets found. I configured the plugins like this:
plugins:
sass:
options:
includePaths: [
'bower_components/bootstrap/scss'
]
postcss:
processors: [
require('autoprefixer')
]
babel:
ignore: [
/^(bower_components|vendor)/
]
uncss:
options:
csspath: 'css/app.css'
htmlroot: 'public'
files: ['index.html']
The source files for the project are located in app: index.html in app/assets, main.scss (imports Bootstrap) and styles.css in app/stylesheets, and app.js in app/javascripts.
Brunch builds this to a folder named public, with styles in public/css/app.css and content in public/index.html. The question is, what is incorrect about the configuration of UnCSS? My understanding of it is that it works on the CSS output from the build, in which case the paths seem correct.
There is a question on SO from 2014 asking pretty much the same thing, but it was never answered.
I had not considered looking at the GitHub issues, wherein one specifically addressed this. In essence, as suggested by #1951FDG:
plugins:
uncss:
options:
ignore: [/\.\bactive\b/]
ignoreSheets: [/fonts.googleapis/]
files: ['public/index.html']
ignore: sample regex to ignore '.active' class
ignoreSheets: sample regex to ignore Google fonts
More importantly, this invocation of UnCSS reads the stylesheets linked in index.html to find the correct CSS-file, then processes it.

Uglify or concat a JavaScript file conditionallly

I have in my Scripts folder a "Lib" folder and an "App" folder.
The Lib folder contains 3rd part library JavaScript files. Some of these are minified without the original sources, others we have the original sources for.
The App folder contains all of our own JavaScript files, all of which are not minified.
I'm new to Grunt but I have a gruntfile which does the following:
Uglifies all the JS files in the Lib folder and produces minified versions with sourcemaps.
Uglifies all the JS files in the App folder and produces minified versions with sourcemaps.
Obvious problem: some of the files in the Lib folder are minified, so minifying them again/generating source maps is a bad idea and can fail for various reasons.
My solution: I run Uglify only on .js files in the Lib folder into lib-unmin.min.js. I then concat all the already minified files into a lib-min.min.js file, then I concat both those files together to get lib.min.js.
The new problem
What if I can't concat the already minified scripts to the end of the other minififed scripts without it breaking?
I have a dependency issue like this:
scripts/lib/a.js (required for b to run)
scripts/lib/b.min.js (required for c to run)
scripts/lib/c.js (required for the App scripts to run)
If I have an array of these file paths in my gruntfile, in that order, what's the easiest way of uglifying/concating all the files into a single minified JS file in that order, making sure we don't attempt to minify the minified file?
What do other developers do in similar situations?
Thanks!
I like to concat the files then uglify all of them together. This way uglify makes sure there aren't duplicate variable values overriding each other when it compresses the variable names.
You can bundle as many files as you want in the concats. Make different concat groups to uglify together and maintain the 'first, second, third, ...' order like this:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
app: {
options: {
sourceMap: true,
sourceMapName: 'build/maps/map.map'
},
files: {
'build/app.min.js': ['build/js/app-first-unmin.js', 'build/js/app-second-min.js', 'build/js/app-third-unmin.js']
}
}
},
concat: {
options: {
separator: ';'
},
firstUnminified: {
src: [
'lib/underscore.js'
],
dest: 'build/js/app-first-unmin.js'
},
secondMinified: {
src: [
'lib/moment.min.js'
],
dest: 'build/js/app-second-min.js'
},
thirdUnminified: {
src: [
'lib/favico.js'
],
dest: 'build/js/app-third-unmin.js'
}
},
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['concat:firstUnminified', 'concat:secondMinified', 'concat:thirdUnminified','uglify']);
};

How can I tell Brunch not to concatenate javascript files?

Does anyone know how to configure Brunch not to concatenate javascript files in the local build?
I want the javascript files copied straight over so that I do not have one large javascript file when debugging.
Here's my current brunch-config.coffee file:
exports.config =
conventions: ignored: /.+\.spec\.js/
files:
javascripts:
joinTo:
'js/app.js': /^app/
'js/vendor.js': /^(vendor|bower_components)/
stylesheets:
joinTo:
'css/common.css': /^app/
templates:
joinTo:
'js/templates.js': /^app/
Place your javascript files into app/assets
Remove javascripts and templates from your brunch config.
That should just copy them over as-is.
Per Paul's comment, it is not possible yet to not combine js files when building locally. Thanks Paul

grunt-usemin block paths not relative to html file?

Having a lot of trouble understand how paths are treated at various points in the configuration and usage of grunt-usemin.
I've got the following repo layout, where the repo root will also be the web app root:
/dashboard/index.html
/Gruntfile.js
/vendor/...some 3rd party CSS and JS...
So the index.html file -> somedomain.com/dashboard/index.html.
The index.html file includes some CSS and JS assets from the /vendor folder. I have grunt configured to put build output in a build folder:
/build/dashboard/index.html
In the index.html file, I have usemin blocks wrapped around all the CSS link and JS script tags:
<!-- build:css(.) app.min.css -->
<!-- build:js(.) app.min.js -->
I had to specify an "alternative search path" with "(.)" so that a script tag for "/vendor/backbone.js" will find it in the right place. Until I did that, it was looking for /dashboard/vendor/backbone.js.
I want the output of processing the CSS/JS assets to be output to build/dashboard/app.min.css and build/dashboard/app.min.js, and included by index.html using a simple relative "app.min.css/js" path.
The problem is, grunt-usemin seems to be using the "app.min.*" path I'm specifying for both contexts in a way that makes it impossible for them to work together:
1) It treats the path as relative to the build directory for purposes of creating the file; the files end up in build/app.min.css and build/app.min.js.
2) It treats the path as relative to the index.html file for purposes of generating the new link/script tags; the browser loads build/dashboard/index.html, which then tries to load "app.min.css", which maps to build/dashboard/app.min.css.
Is there a solution?
I'm really late to the party, but I was also extremely frustrated by this issue and didn't find any satisfying fixes or work arounds. So I worked out some pretty dirty tricks to hopefully better work around this issue. So I'd like to share it with you.
First of all, let's quickly review why this issue happens. When usemin generates output JS/CSS files, it performs a simple path join between your dest directory and the output directory you specified in your usemin block. So if dest is build and usemin block is
<!-- build:css(.) app.min.css -->
then it joins build with app.min.css to spit out the output file at build/app.min.css
But then the usemin task simply replaces the path in your block to you end up with
<link rel="stylesheet" href="app.min.css"/>
which is now linking the wrong directory since your HTML file is under build/dashboard/index.html
So my work around revolves around this idea: what if dest directory is relative to where the HTML file is located? Wouldn't that solve this issue? So given the above example, what if dest is build/dashboard? You can see that it will spit out the output file location and link it correctly. Keep in mind that you are supposed to create a copy task to copy over your HTML files, so make sure your HTML file is copied to build/dashboard/index.html as before.
Of course, the next question would be what if I have HTML files in multiple directories? Wouldn't that be super painful and unintuitive to create a useminPrepare target for each directory, where HTML files could reside? This is why I create a very special grunt task just for working around this issue while I was creating my own grunt scaffolding. I call it useminPreparePrepare Yes, it's deliberately named stupidly, because I'm hoping to remove this thing altogether one day when usemin people make an actual fix for this issue.
As its name suggests, this is a task to prepare useminPrepare configs. It does exactly what I described above. All of its configs mirror useminPrepare configs (in fact, most of them are simply copied over to useminPrepare), with one exception: you need to specify a src directory to identify the root directory of all of your sources so that it can generate relative path to the HTML files. So in your example src: "." will be fine. To use useminPreparePrepare, import it into your build first (you may want to just copy and paste my code, I don't mind), rename your useminPrepare task to useminPreparePrepare and add src property that I just mentioned. Make sure you run useminPreparePrepare with whatever target you like, then immediately run useminPrepare without specifying target so that all of its targets are run. This is because useminPreparePrepare will generate one target for each directory relative to where HTML files are found and copies over your configs for the useminPreparePrepare target your ran. This way, your config can simply look for all HTML files.
Example
"useminPreparePrepare": {
// Search for HTML files under dashboard even though src is .
// because we want to avoid including files generated under build directory.
html: "dashboard/**/*.html",
options: {
src: ".",
dest: "build",
...
"usemin": {
html: ["build/**/*.html"],
...
"copy": {
html: {
files: [{
expand: true,
src: ["dashboard/**/*.html"],
dest: "build"
}
]
},
...
Hope this helps! Have a good day.
EDIT: I realized that given the above example, if you actually include all HTML files from current directory, you will include the generated HTML files too if they are not cleaned ahead of time. So either you clean them ahead of them or look under dashboard directory. I'd recommend separating src and dest directories so that config could look a lot more intuitively.
I don't like it, but the only way I've found to make it work so far is to specify a full path:
<!-- build:css(.) /dashboard/app.min.css -->
<!-- build:js(.) /dashboard/app.min.js -->
The leads to the app* files being in /build/dashboard alongside index.html (which is where I want them), and index.html ends up with the following tags:
<link rel="stylesheet" href="/dashboard/app.min.css">
<script src="/dashboard/app.min.js"></script>
It means the dashboard app is now acutely aware of it's location within the whole, so you can't just rename or relocate it's position in the tree without updating those paths.

Loading vendor javascript as modules

I'm working on an application built with Brunch. I would like to load some* of the vendor-supplied javascript as modules, so that I can require them in my code, rather than relying on global variables. Is there some way to do this, without copying all the vendor code into my app directory?
I tried creating a vendorlib directory, but brunch doesn't seem to look anywhere bu app and vendor. I also tried making a vendor/modules directory, but brunch seems to not wrap anything found under vendor (even when I convinced it to combine those files with the files other modules found under app.)
*The "some" that I'm working on right now are Chaplin, Backbone and Underscore. If I get those to work, I'll move more over later.
You can override config.modules.wrapper and make it wrap, for example, all files in vendor/modules directory. Or you can make add more directories that are handled by brunch to config.paths.watched.
For those following along at home, this is what my config.coffee eventually looked like:
paths:
watched: ['app','vendor','test','vendorlib']
files:
javascripts:
joinTo:
'javascripts/app.js': /^app/
'javascripts/vendor.js': /^vendor/
'test/javascripts/test.js': /^test[\\/](?!vendor)/
'test/javascripts/test-vendor.js': /^test[\\/](?=vendor)/
order:
# Files in `vendor` directories are compiled before other files
# even if they aren't specified in order.before.
before: [
'vendor/scripts/console-polyfill.js',
]
after: [
'test/vendor/scripts/test-helper.js'
]
stylesheets:
joinTo:
'stylesheets/app.css': /^(app|vendor)/
'test/stylesheets/test.css': /^test/
order:
after: ['vendor/styles/helpers.css']
templates:
joinTo: 'javascripts/app.js'
modules:
nameCleaner: (path) ->
path.replace(/^(app|vendorlib)\//, '')
This lets me populate a vendorlib directory with modules from vendors that support loading as modules. I currently have Chaplin, jQuery, and Backbone in there. I had to rename them not to include the version numbers.

Resources