Django Pipeline, Heroku, and SASS - css

I've been trying to get django-pipeline setup so that I can compile and concat my assets. I would also like to remove the compiled css files from my repository to avoid merge conflicts in pull requests.
I've been trying to get django-pipeline to compile the files as part of the deploy process but can't figure this out. I use SASS to write my CSS. My pipeline settings look like this:
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
PIPELINE_CSS = {
'main': {
'source_filenames': (
'sass/blah.scss',
'sass/main.scss',
),
'output_filename': 'css/main.css',
'extra_context': {
'media': 'screen',
},
},
}
PIPELINE_COMPILERS = (
'pipeline.compilers.sass.SASSCompiler',
)
This works great locally, and generates .css files in my /sass folder, which are then combined to make the main.css file. If I check those CSS files into my git repository and push to Heroku, it also works fine. However, if I ignore them, which I would like to do so that I'm not committing compiled files, then django-pipeline can't find the files to combine. I'm not sure how I can get the sass compilation working on Heroku and I can't find anything about it.
I can provide more information about my setup if needed, hopefully somebody knows something about this!

OK, here's how I got this working using Compass to compile my SASS files.
Use multiple Heroku buildpacks - Heroku Buildpack Multi
Put the following in your .buildpacks file
https://github.com/heroku/heroku-buildpack-ruby.git
https://github.com/heroku/heroku-buildpack-nodejs
https://github.com/heroku/heroku-buildpack-python.git
Create a Gemfile with compass and any other requirements you have. Here's mine:
source 'https://rubygems.org'
ruby '1.9.3'
gem 'bootstrap-sass'
gem 'compass'
Create a config.rb file. Here's mine. As you can see it, requires the bootstrap-sass that I included in my Gemfile:
# Require any additional compass plugins here.
require 'bootstrap-sass'
# Set this to the root of your project when deployed:
http_path = "/"
css_dir = "app_folder/static/css"
sass_dir = "app_folder/static/sass"
images_dir = "app_folder/static/images"
output_style = :compact
more details on config.rb can be found here
Install node packages (django-pipeline wants yuglify). You'll need a package.json file:
{
"dependencies": {
"yuglify": "0.1.4"
},
"engines": {
"node": "0.10.x",
"npm": "1.3.x"
},
"repository": {
"type": "git",
"url": "your repo url"
}
}
almost ready...
when Heroku runs the ruby buildpack, it will look for a rake task called assets:precompile. So now you'll need to add a Rakefile with the following:
namespace 'assets' do
desc 'Updates the stylesheets generated by Sass/Compass'
task :precompile do
print %x(compass compile --time)
end
end
this will put compile your stylesheets. You need to make sure you set the output (back in config.rb) to the place that django-pipeline is looking for CSS files (shown in the original question).
You should get rid of this part in the original question as django-pipeline isn't compiling your SASS for you:
PIPELINE_COMPILERS = (
'pipeline.compilers.sass.SASSCompiler',
)
That should be it! Deploys should just work now, and it didn't really add a significant amount of time to my deploy process.
All in all, it amounts to a lot of setup, but for me it was well worth it as I no longer have to commit compiled files into the repository, which was causing a lot of merge conflicts when working with branches and pull requests.
I would like to figure out how to do this using only two buildpacks (obviously only one would be ideal but I don't know if it's possible). The problem is trying to find binary paths so that pipeline can do it's thing when it doesn't find the defaults. I'm not sure if the reason I can't do this is because of how Heroku is installing things, or because there is a bug in django-pipeline, but right now this is good enough for me.
If you try this and it doesn't work for you, let me know, if I missed something I'm happy to make updates.

I don't want to take away from your excellent solution, but I tried this today and found a few differences that made things simpler for me - likely due to updates in django-pipeline and/or Heroku. My full solution is below, in case anyone else comes looking.
Add the 3 buildpacks to Heroku:
heroku buildpacks:set https://github.com/heroku/heroku-buildpack-ruby.git
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-nodejs
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-python.git
Add django-pipeline and django-pipeline-compass to requirements.txt:
django-pipeline==1.5.2
django-pipeline-compass==0.1.5
Create a Gemfile to install Sass:
source 'https://rubygems.org'
ruby '2.1.5'
gem 'bootstrap-sass'
Create a package.json file to install Yuglify:
{
"dependencies": {
"yuglify": "0.1.4"
},
"engines": {
"node": "0.10.x",
"npm": "1.4.x"
}
}
I did not need a Rakefile or config.rb.
For reference, here are relevant settings from my settings.py:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, '_generated_media')
STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'pipeline.finders.PipelineFinder',
)
PIPELINE_COMPILERS = (
'pipeline_compass.compiler.CompassCompiler',
)
PIPELINE_YUGLIFY_BINARY = os.path.join(BASE_DIR, 'node_modules', '.bin', 'yuglify')
And I also had to add this entry to urls.py:
url(r'^static/(?P<path>.*)$', serve, kwargs={'document_root': settings.STATIC_ROOT})
Hope it helps someone!

You may need to set PIPELINE_SASS_BINARY so that django-pipeline can find your SASS compiler.

You can use the libsass compiler for django-pipeline that uses Sass packaged as a Python package:
pip install libsasscompiler
Update your config:
PIPELINE['COMPILERS'] = (
'libsasscompiler.LibSassCompiler',
)
The default Yuglify compressor is also a problem on Heroku, which you can temporarily overcome by disabling it. This is my config for enabling Sass on Django for example:
PIPELINE = {
'COMPILERS': (
'libsasscompiler.LibSassCompiler',
),
'STYLESHEETS': {
'main': {
'source_filenames': (
'styles/main.scss',
),
'output_filename': 'css/main.css'
},
},
# disable the default Yuglify compressor not available on Heroku
'CSS_COMPRESSOR': 'pipeline.compressors.NoopCompressor',
'JS_COMPRESSOR': 'pipeline.compressors.NoopCompressor'
}
The longer-term solution would be to move towards a JS-only build toolchain (as most projects are doing). Rails integrates pretty nicely with Webpack for example and is maintained by the same team. Until that happens in Django (if ever) and trickles into the Heroku Python builpack, you can use Heroku's multiple buildpacks and add an official Node buildpack step that runs npm install; npm run build for you.

Related

Parsing error : Cannot find module 'next/babel'

Update 1 : Updated the latest working solution to #Jeevan Rupacha answer, please scroll below to check it out.
I have been encountering this error on every single new Next.js project that I create. The page can be compiled without any problem, it just keeps on showing as error on the first line in every js file.
Parsing error: Cannot find module 'next/babel'
Require stack:
D:\app\next_app\ratu-seo\node_modules\next\dist\compiled\babel\bundle.js
D:\app\next_app\ratu-seo\node_modules\next\dist\compiled\babel\eslint-parser.js
D:\app\next_app\ratu-seo\node_modules\eslint-config-next\parser.js
D:\app\next_app\ratu-seo\node_modules#eslint\eslintrc\lib\config-array-factory.js
D:\app\next_app\ratu-seo\node_modules#eslint\eslintrc\lib\index.js
D:\app\next_app\ratu-seo\node_modules\eslint\lib\cli-engine\cli-engine.js
D:\app\next_app\ratu-seo\node_modules\eslint\lib\cli-engine\index.js
D:\app\next_app\ratu-seo\node_modules\eslint\lib\api.js
c:\Users\Admin.vscode\extensions\dbaeumer.vscode-eslint-2.1.23\server\out\eslintServer.js
Create file called .babelrc in your root directory and add this code:
{
"presets": ["next/babel"],
"plugins": []
}
And in .eslintrc, replace the existing code with:
{
"extends": ["next/babel","next/core-web-vitals"]
}
I had this same problem - but only when I wasn't opening the project folder directly. It appears to be related to how ESLint needs to be configured for workspaces.
In addition, the currently accepted answer works for VSCode but breaks npm run lint for me.
TL;DR - see this answer which points to this blog. This fixed it for me.
Some Details
For example, if I have:
~
| -- some_folder
| | -- project_1
| | -- project_2
| ...files relating to both projects...
I'll often just cd ~/some_folder && code .
But then I get the same error you're experiencing. However, if I cd ~/some_folder/project_1 && code . then everything works fine.
If that's the case for you as well, then what you need (as described in the links above) is to:
Create a workspace config
Specify folders where you need ESLint to run
You can do this easily from VSCode. The net result (following my example above) is a file named ~/some_folder/.vscode/settings.json with contents
{
"eslint.workingDirectories": [
"./project_1",
"./project_2"
]
}
Note: You don't need to create extra .babelrc file
In your NextJS Project you have this file , named .eslintrc.json,
In this file
You have following code
{
"extends": "next/core-web-vitals"
}
Replace it with
{
"extends": ["next/babel","next/core-web-vitals"]
}
Note: If you only replace with
{
"extends": ["next/babel"]
}
The red error sign will go but the code won't compile and gives compile error.
For Nextjs 12 add prettier in .eslintrc.json file inside your root folder.
{
"extends": ["next/core-web-vitals", "prettier"]
}
In my case, the issue occurs when I code in VSCode and use pnpm as the package manager, I tried lots of methods in StackOverflow, and finally, I find out that it's the duty of the VSCode ESLint plugin.
So, to fix the problem without uninstalling the plugin, add the following configuration in the .vscode/settings.json and reload your editor.
{
"eslint.packageManager": "pnpm"
}
Using Next.js, TypeScript, and Tailwind CSS, I updated the .eslintrc.json file with:
{
"extends": ["next/babel", "next/core-web-vitals"]
}
then ctrl + shift + p and search for ESLint: Restart ESLint Server.
It worked for me by just adding prettier in .eslintrc file.
{
"extends": ["next", "prettier"]
}
Try updating the .eslintrc.json file to
{
"extends": ["next", "prettier","next/core-web-vitals"],
"plugins": ["prettier"]
}
Also install prettier plugin if you don't have it already
npm install eslint-plugin-prettier#latest --save-dev
Don't have to include .babelrc file as it will replace Nextjs SWC compiler
S
I had this same problem - Close the IDE and reopen it with the project folder !!
My Problem
I found this error in project with PNPM, ESLint, and Monorepo architecture using Turborepo.
My Solution
add this into the ESLint config file:
parserOptions: {
babelOptions: {
presets: [require.resolve('next/babel')],
},
},
You can also always try updating React and then Next. I had the same error message then updated them both and now my app is working fine.
Upgrade React version to latest
Most applications already use the latest version of React, with Next.js 11 the minimum React version has been updated to 17.0.2.
To upgrade you can run the following command:
npm install react#latest react-dom#latest
Or using yarn:
yarn add react#latest react-dom#latest
Upgrade Next.js version to latest
To upgrade you can run the following command in the terminal:
npm install next#latest
or
yarn add next#latest
Just had this issue with the Nextjs app and the following worked for me. I no longer have issue with next/babel and I can run yarn lint.
Add prettier to your project
yarn add --dev eslint-config-prettier
Update your eslint config as follows
{
"extends": ["prettier", "next/core-web-vitals"]
}
Add global vscode settings and include your project path
{
"eslint.workingDirectories": ["./your-project"]
}
In my case I had to disable VSCode ESLint extension.
Unfortunately when I added ["next/babel"] in extends, the npm run lint stopped working and Eslint in vscode did not underlining any abnormalities.
ctrl + shift + p
TypeScript: Restart TS server
Really, just adding prettier to "extends": ["next/core-web-vitals] to have something like ==> {"extends": ["next/core-web-vitals", "prettier"]}, gets rid of the error, without having to create an extra .babelrc file. But another research that needs to be done, is to know, if there are any downsides to doing it, and i think the answer is NO
In my project, i just run yarn add #babel/core and run
ctrl + shift + p in vscode, excute ESLint: Restart ESlint Server
ESLint: Restart ESlint Server
it works, and npm run lint works fine too.
> Executing task: yarn run lint <
✔ No ESLint warnings or errors
In my case, the problem is that I added "eslint.packageManager": "yarn" to the setting.json of VSCode before, and I tried to use the same setup within a new project managed with pnpm. After adding "eslint.packageManager": "pnpm" for the new workspace, and reload window, than the issue's gone.
I've tried adding "extends": ["next/babel", "next/core-web-vitals", "prettier"] to .eslintrc.js, it will fix the error only within VSCode, but will cause the other error when building my Next.js app.

Building library with imports from another library using NX Monorepo

Here is the case. I am using Nrwl NX Monorepo. I have 2 libraries lib-a and lib-b both are publishable libraries created via NX. Now I create a MyClass.ts in lib-a. Naturally under paths in workspace/tsconfig.json paths NX creates an alias to this lib-a ("#workspace/lib-a": ["libs/lib-a/src/index.ts"]). So far so good.
Now we can use this class anywhere within the workspace/monorepo by importing it "import { MyClass } from '#workspace/lib-a';
Unfortunately we can not build lib-b which is importing MyClass. When we try to do it we get the bellow error. So question is how can we build lib-b ?
PS It seems strange that NX monorepo actually don't support such a common scenario linking 2 publishable libs.
"error TS6059: File "d:/workspace/libs/lib-a/src/index.ts" is not under 'rootDir' "d:\workspace\libs\lib-b\src" rootDir is expected to contain all source files"
Try adding
"paths": { "#workspace/*": ["dist/libs/*"] }
into your tsconfig.lib.json files. This should resolve the problem.
Try this solution. Not sure it's official, but in my case it's working well.
3 problems should be resolved:
TypeScript paths
Compiled JS paths
Working directory
First. TypeScript paths is resolved by adding "paths" into workspace/tsconfig.lib.json. NX does it automatically while lib gen. Look answer from Radovan Skendzic.
Second. Problem with compiled JS paths very good described here: Typescript paths not working in an Express project. So you need to install tsconfig-paths into your workspace:
yarn add -D tsconfig-paths
Third. Considering nx run [project]:[target] is working in workspace/ directory you should set CWD to libs/lib-b home directory - to find correct tsconfig.json
So, finally, you have the following executor (add this to your lib-b/project.json) that should work:
"targets": {
"start-dev": {
"executor": "#nrwl/workspace:run-commands",
"options": {
"commands": [
"nodemon -e ts,js --exec ts-node -r tsconfig-paths/register src/index.ts"
],
"cwd": "libs/lib-b"
}
},
...
}
Command to run:
nx run lib-b:start-dev
Don't override "baseUrl" and "paths" in any of child tsconfig!
Put all of your "paths" in tsconfig.base.ts!
Try adding lib-a as an implicit dependency of lib-b, add the line below into the libs/lib-b/project.json file and see what happens:
"implicitDependencies": ["lib-a"]
Running nx graph should show you a graph that should look something like this (do not consider the name of the libraries):
After that you should be able to build both libraries, I hope it works with you as well.

Is there any way to tell angular-cli (for angular 2) to generate minified version of css?

As the title says, when I run "ng serve" angular-cli generates normal css whereas I expect to get the minified version.
Is there any specific setting to use for angular-cli-build, or some additional plugin to install and use?
This is my angular-cli-build.js
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'zone.js/dist/**/*.+(js|js.map)',
'es6-shim/es6-shim.js',
'reflect-metadata/**/*.+(ts|js|js.map)',
'rxjs/**/*.+(js|js.map)',
'#angular/**/*.+(js|js.map)',
'angular2-cookie/**/*.js'
]
});
};
ng build --prod --env=prod
or
ng serve --prod
Will minify and add a file hash for you.
the --prod tells it to minify hash, and gzip.
the --env=prod tells it to use your prod environment constants file.
which would look like this
You can use
# --env=<your_env>
# --no-sourcemap
# minify => ./minify.js
ng build --env=prod --no-sourcemap && node minify
minify.js
// npm i --save-dev minifier fs-jetpack
const jetpack = require('fs-jetpack');
const path = require('path');
const minifier = require('minifier');
const files = jetpack.list(path.join(__dirname, 'dist'));
console.log(files);
for (const file of files) {
if (/.*(\.js|\.css)$/g.test(file)) {
console.log(`Start ${file}`);
const filePath = path.join(__dirname, 'dist', file);
minifier.minify(filePath, {output: filePath});
}
}
console.log('End');
James' commands DO work and DO minify even when using ng serve --prod.
However you may see something like the following in Chrome and get confused:
That doesn't look minified does it!
Look more carefully and you'll see js:formatted indicating that the pretty print feature was enabled.
Opening the URL http://localhost:4200/main.5082a3da36a8d45dfa42.js directly in a new tab showed me that the CLI was indeed minifying it fully.
You can click the {} icon to turn this feature off, but it seems to like to disappear once the code has been pretty printed so you may need to reload the page and click it quickly.
In 2020 it is just enough to use --prod flag, when building project:
ng build --prod

Command-line argument as var in Sass, for hardcoded CDN URL's on compile

For local HTML/Sass/Css developement we use libsass (via Grunt) to compile our Sass files to Css. The Css background-image URL's are root relative.
Sass
$dir-img: /img;
.header {
background-image: url(#{$dir-img}/header.jpg);
}
We'd like to change the URL to use a CDN when compiling for production server:
background-image: url(http://media.website.com/img/header.jpg);
Is there some solution to pass-in a command-line argument TO Sass so Sass can use a Sass #IF to switch the root-relative URL's to hard-coded CDN like URL's. Something like:
Command-line:
grunt sass:dist --cdnurl="http://media.website.com/img/"
Sass
Then Sass checks if the command-line argument was given:
#if using CDN {
$dir-img: cdnurl;
#else {
$dir-img: /img;
}
And then all IMG url's would use the CDN URL.
I couldn't find anything on libass command-line options to pass said vars. to Sass.
But eventually came up with a working version of my own! Have Grunt write a Sass config partial.
Pretty simple actually if your already using Grunt and Sass. We'd already had NodeJS and Grunt-cli installed on our staging (test) -server.
Sass setup
In Sass we already used a (larger) Sass config file which holds a few vars like:
_config.scss
$dir-font: '/assets/assets/fonts';
$dir-htc: '/assets/htc';
$dir-img: '/assets/images';
This config file holds much more config settings but I've updated these vars. in this config file to:
#import "_sourcepaths";
$dir-font: '/assets/fonts' !default;
$dir-htc: '/assets/htc' !default;
$dir-img: '/assets/images' !default;
Note the #import partial of _sourcepaths.scss. This smaller partial file is generated by Grunt. The Sass !default; is used as fallback vars. or you might not even need these anymore (are overwritten by Grunt).
Grunt setup
On the Grunt side I added a custom task that is only executed on our staging (or test) -server (for example during a build process). On our local machine we keep using root-relative paths for local development.
Grunt custom target configuration
module.exports = function(grunt) {
grunt.initConfig({
writeSassConfig: {
options: {
scss: './assets/scss/partials/_sourcepaths.scss',
dirFont: '/assets/fonts',
dirHtc: '/assets/htc',
dirImg: '/assets/images'
},
cdn: {
//pathprefix: 'http://cdn.website.com'
pathprefix: grunt.option('pathprefix') || ''
}
}
}
});
Example cdn Grunt target with hardcoded (http://cdn.website.com) or dynamic (via grunt.option command-line argument) pathprefix. See below at 'Running the Grunt task' how to run this. It also has a fallback || '' to empty, which actually resets the paths in the Sass config file to root-relative URL's.
Grunt custom task
Then the required Grunt task (for configuration above). This Grunt task writes the Sass partial to disk.
grunt.registerMultiTask('writeSassConfig', 'Write Sass config file to change source paths', function(){
grunt.config.requires(
this.name + '.options.scss',
this.name + '.options.dirFont',
this.name + '.options.dirHtc',
this.name + '.options.dirImg',
);
// Create Sass vars
var _thisOptions = this.options(),
pathprefix = this.data.pathprefix || '',
contents = "// Generated by Grunt for dynamic paths like a CDN server\n";
contents += "$dir-font: '" + pathprefix + _thisOptions.dirFont + "';\n";
contents += "$dir-htc: '" + pathprefix + _thisOptions.dirHtc + "';\n";
contents += "$dir-img: '" + pathprefix + _thisOptions.dirImg + "';\n";
grunt.file.write(_thisOptions.scss, contents);
});
Grunt aliased task
This creates a custom chained workflow of two tasks running after each other. The sass:dist is a regular Grunt task and target via grunt-sass (libsass) plugin. You are probably already using this.
grunt.registerTask('build-sasscdn', 'Generate Sass config for different Sass paths like a CDN server path', function(){
grunt.task.run(
'writeSassConfig',
'sass:dist'
);
});
Running the custom Grunt task
The pathprefix var., via grunt.option('pathprefix'), in above Grunt custom target is provided via grunt command-line argument:
grunt build-sasscdn --pathprefix="https://cdn.website.com"
This domainname can be changed by the staging (test) -server server-side-scripting language (like .NET/PHP/Ruby). The Sass config file _sourcepaths.scss is now changed by Grunt to:
_sourcepaths.scss
$dir-font: 'https://cdn.website.com/assets/fonts';
$dir-htc: 'https://cdn.website.com/assets/htc';
$dir-img: 'https://cdn.website.com/assets/images';
Remember that _sourcepaths.scss is imported by Sass. The Grunt alias task then runs the usual sass:dist target, which just re-compiles the Sass (on the staging / test server) WITH updated hard-coded CDN domain name paths in the Css.

How to compile .less files on save in Visual Studio 2015 (preview)

Ok, so I've created a new ASP.Net 5/MVC 6 project in Visual Studio 2015 Preview. In keeping with our current method of doing things, for styling I want to use .less files. Creating the files is straightforward, but Web Essentials no longer compiles them.
So my question is this: what precisely do I need to do to get my .css files generated when I save the .less files?
Based on my adventures getting Typescript to work nicely, I will have to use Grunt to accomplish this task, but I am brand-new to Grunt and so I'm not sure how one would do it?
Please help!
With VS 2015 Web Essential is split into multiple extensions you can download
the Web Compiler extension from here and it also has details on how to use it.
It is certainly not elegant as it used to be, but if you are using existing project and want to use a compiler for LESS then this may do the basic job.
So here's how to do it (compile on build and non-elegant compile on save):
Step 1
Open up your package.json file (it's in the root of your project) and add these lines:
"grunt-contrib-less": "^1.0.0",
"less": "^2.1.2"
Obviously you can change the version numbers (you'll get helpful intellisense), these are just the current versions.
Step 2
Right-click on the NPM folder (under Dependencies) and click Restore Packages. This will install less and grunt-contrib-less.
Step 3
Once those packages are restored, go to your gruntfile.js file (again, in the root of the project). Here, you'll need to add the following section to grunt.initConfig
less: {
development: {
options: {
paths: ["importfolder"]
},
files: {
"wwwroot/destinationfolder/destinationfilename.css": "sourcefolder/sourcefile.less"
}
}
}
You'll also need to add this line near the end of gruntfile.js:
grunt.loadNpmTasks("grunt-contrib-less");
Step 4
Then just go to View->Other Windows->Task Runner Explorer in the menu hit the refresh icon/button, then right-click on less under Tasks and go to Bindings and tick After Build.
Hooray, now less files will compile and we (I) learned about grunt, which seems really powerful.
Step 5: Compiling on save
I still haven't got this working to my satisfaction, but here's what I've got so far:
As above, add another NPM package grunt-contrib-watch (add to package.json, then restore packages).
Then add a watch section in gruntfile.js, like this (obviously this can work for other types of files as well):
watch: {
less: {
files: ["sourcefolder/*.less"],
tasks: ["less"],
options: {
livereload: true
}
}
}
So you'll now have something like this in your gruntfile.js:
/// <binding AfterBuild='typescript' />
// This file in the main entry point for defining grunt tasks and using grunt plugins.
// Click here to learn more. http://go.microsoft.com/fwlink/?LinkID=513275&clcid=0x409
module.exports = function (grunt) {
grunt.initConfig({
bower: {
install: {
options: {
targetDir: "wwwroot/lib",
layout: "byComponent",
cleanTargetDir: false
}
}
},
watch: {
less: {
files: ["less/*.less"],
tasks: ["less"],
options: {
livereload: true
}
}
},
less: {
development: {
options: {
paths: ["less"]
},
files: {
"wwwroot/css/style.css": "less/style.less"
}
}
}
});
// This command registers the default task which will install bower packages into wwwroot/lib
grunt.registerTask("default", ["bower:install"]);
// The following line loads the grunt plugins.
// This line needs to be at the end of this this file.
grunt.loadNpmTasks("grunt-bower-task");
grunt.loadNpmTasks("grunt-contrib-less");
grunt.loadNpmTasks("grunt-contrib-watch");
};
One can then simply set this task to run on Project Open (right-click on watch under Tasks in the Task Runner Explorer (it's under View->Other Windows in the top menu) and you're done. I would expect you'd have to close and re-open the project/solution to get this to kick in, otherwise you can manually run the task.
(Note: there is now a new question asked here directly concerning sass. I tried to alter the question and tags in this question to include sass, but someone didn't allow it.)
I would like to add the answer to the same question for sass (.scss). The answer is so related I think these may best be combined as two answers in this same post (if you disagree, please let me know; else, we might add "or sass" in the post title?). As such, see Maverick's answer for some fuller details, here's the nutshell for sass:
(Pre-step for Empty Projects)
If you started with an empty project, first add Grunt and Bower:
Right click solution -> Add -> 'Grunt and Bower to Project' (then wait for a minute for it to all install)
package.json:
"devDependencies": {
"grunt": "^0.4.5",
"grunt-bower-task": "^0.4.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-contrib-sass": "^0.9.2"
}
(FYI: grunt-contrib-sass link)
Then:
Dependencies -> right-click NPM -> Restore Packages.
gruntfile.js
1) Add or make sure these three lines are registered near the bottom (as NPM tasks):
grunt.loadNpmTasks("grunt-bower-task");
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-sass");
2) Again in gruntfile.js, add init configurations, something like the following.
{ Caveat: I am no expert on such configurations. I found the sass configuration on an excellent blog post some time ago that I can't locate at this time in order to give credit. The key was I wanted to find all files in the project within a certain folder (plus descendants). The following does that (notice "someSourceFolder/**/*.scss", and see important related note here). }
// ... after bower in grunt.initConfig ...
"default": {
"files": [
{
"expand": true,
"src": [ "someSourceFolder/**/*.scss" ],
"dest": "wwwroot/coolbeans", // or "<%= src %>" for output to the same (source) folder
"ext": ".css"
}
]
},
"watch": {
"sass": {
"files": [ "someSourceFolder/**/*.scss" ],
"tasks": [ "sass" ],
"options": {
"livereload": true
}
}
}
Now follow the instructions for Task Runner Explorer as given in the other answer. Make sure to close and reopen project. It seems you have to run (double click) 'watch' (under 'Tasks') every time the project is started to get the watch watching, but then it works on subsequent saves.

Resources