How to enable Stylus url() rewrites - javascript

I'm trying to get stylus urls to work. I would like to convert the url('/path/to/img.png') to convert to the base64 encoded form.
I'm trying to follow the documentation here, but it's not helping me much.
I tried adding the require bit and the example functions, importing url, but not sure how to enable this thing.
How do I get this to work?
UPDATE:
Trying to use grunt-image-embed plugin.
Here is my grunt config:
imageEmbed: {
dist: {
src: [ "./public/local/css/images.css" ],
dest: "./public/prod/css/images.css",
options: {
deleteAfterEncoding : false
}
}
},
And the css contains:
#footer-social .youtube {
width: 18px;
background-image: url('/img/youtube-icon.png');
}
Which produces the error:
Warning: File C:\path\...\grunt-image-embed\tasks\lib\img\youtube-icon.png
does not exist Use --force to continue.
If I remove the background-image line it all works and goes through fine. I can't modify the paths in the css because on local we use the relative path to the actual image.

try this:
function compile(str, path) {
return stylus(str)
.define('url', stylus.url({
paths : [__dirname + '/public'],
limit : 10000
}));
}
From here:
http://bengourley.co.uk/using-stylus
It worked for me here:
https://github.com/MichaelJCole/wintersmith-stylus/blob/master/plugin.coffee
It's coffeescript, and the interesting part is this:
stylus(#_text, options)
.use(nib())
.define('url', stylus.url(
paths : [__dirname + '/public']
limit : locals.inlineSpriteMaxBytes || 0 ) )
.render (err, css) ->
if err
callback err
else
callback null, new Buffer css

I do not know how it makes no a stylus, but you can use this [1]: http://docs.emmet.io/actions/base64/

I think you'll find this grunt plugin to be exactly what you need; grunt image embed. Works for both images and fonts. From the docs:
grunt.initConfig({
imageEmbed: {
dist: {
src: [ "css/styles.css" ],
dest: "css/output.css",
options: {
deleteAfterEncoding : false
}
}
}
});

Related

Modify JS files using another JS file

How can I edit a JS file (containing a JSON object) using another JS file?
Example:
JS file to be edited (eslintrc.js):
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true
}
}
And I want to let's say add additional configuration lets say in:
env: {
browser: true,
node: true
}
I tried doing something like:
fs = require('fs');
var m = JSON.parse(fs.readFileSync('.eslintrc.js'));
console.log(m)
But of course, as expected, I am getting errors.
undefined:1
module.exports = {
^
SyntaxError: Unexpected token m in JSON at position 0
at JSON.parse (<anonymous>)
To also add, this is not the only file I need to update. There are several others that look similar in nature but not exactly the same such as:
module.exports = function (ctx) {
return {
// --> boot files are part of "main.js"
boot: [
],
css: [
'custom.scss'
]
}
}
How can I open the JS file and be able to edit the JSON object inside without distoring the actual JS file?
Thank you!
You must eliminate 'module.exports =' from eslintrc.js in order to parse it with JSON.parse function.

Dynamically set script tag through Grunt based on ENV

During my Grunt build process, I would like to set the script tag in my index.html which references the Google Maps API dynamically based on process.env.NODE_ENV.
Something like:
let googleMapsUrl;
if (process.env.NODE_ENV === 'development') {
googleMapsUrl = '//maps.googleaps.com/maps/api/js?v=3.exp&libraries=visualization';
} else {
googleMapsUrl = `//maps.googleaps.com/maps/api/js?key=${process.env.GOOGLE_MAPS_API_KEY}v=3.exp&libraries=visualization`;
}
My question is how do I then insert googleMapsUrl into a script tag in index.html like so: <script src=googleMapsUrl></script>
There are many options that you could use. From simple, like grunt-replace to more advanced ones like grunt-processhtml. I will describe the first one as it’s a good option for simple tasks and requires just a simple configuration.
Using grunt-replace
grunt-replace will search for simple variable definitions like ##foo in your source files, and replace those variables with your supplied value or the returning value from a callback.
First install the plugin using npm install grunt-replace --save-dev
Then configure the task as follows:
replace: {
dist: {
options: {
patterns: [
{
match: 'gmaps',
replacement: function() {
var googleMapsUrl;
if(process.env.NODE_ENV === 'development') {
googleMapsUrl = '//maps.googleaps.com/maps/api/js?v=3.exp&libraries=visualization';
} else {
googleMapsUrl = '//maps.googleaps.com/maps/api/js?key=' + process.env.GOOGLE_MAPS_API_KEY + 'v=3.exp&libraries=visualization';
}
return googleMapsUrl;
}
}
]
},
files: [
{
expand: true,
flatten: true,
src: ['path/to/your/source/file.html'], dest: 'destination/folder/'
}
]
}
}
Load the plugin using grunt.loadNpmTasks('grunt-replace') and then add it to your build process.
On your source files just add the defined variable as your script source:
<script src="##gmaps"></script>
The task will replace ##gmaps with the returning value from the defined callback.
Hope it helps.
More about plugin can be found here.

Grunt run curl on changed file only

I'm trying to upload a file to a server on change using grunt-run and curl. I can get it to work if I hard code the file name into the actual task, but I'm trying to run it based on the file that changed...here's my grunt file so far (stripped down to the parts related to this question).
module.exports = function(grunt) {
var config = require('./config.json');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
less : {
files : ['front-end/less/**/*.less'],
tasks : ['newer:less','sync:css','run:deploy_less_files']
},
},
less: {
development: {
options: {
paths: ['front-end/_builds/css'],
sourceMap : true,
},
files: [{
cwd: "front-end/less",
expand : true,
src : [ '**/*.less', '!_settings.less'],
dest : "front-end/_builds/css",
ext: ".css"
}]
},
},
sync : {
target: {},
css : {
expand: true,
flatten :true,
verbose: true,
cwd : "front-end/_builds/css/",
src : "**/*.css",
dest : "target/css/"
},
},
run : {
deploy_less_files : {}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-sync');
grunt.loadNpmTasks('grunt-run');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-newer');
grunt.registerTask('default', ['watch']);
grunt.event.on('watch', function(action, filepath, target) {
if (target == "less") {
grunt.config.set('run.deploy_less_files.exec','curl -u ' + config.credentials.user + ':' + config.credentials.pw + ' -T ' + filepath + ' http://localhost:8080/assets/less/');
grunt.task.run("run:deploy_less_files");
}
});
}
Here's what I am trying to do in order:
Watch all LESS files in /front-end/less
If a file changes, compile it to css and place in front-end/_builds/css directory
Sync the contents of front-end/_builds/css with my target/css directory.
Upload the file via curl to my localhost.
Ideally, I'd like to just grab the css file from either my target or the _builds directory and upload it to my localhost, but I can sort that out if I can get this part working.
Any help would be appreciated. Thanks.
See this comment in the grunt-contrib-watch github repo. Excerpts from it read:
"Don't use grunt.event.on('watch') to run your tasks."
and...
"The watch event is not intended for running tasks."
However, you can utilize the grunt.event.on('watch', ...) listener to configure the exec property.
The following gist shows how to meet your requirement:
Gruntfile.js
module.exports = function(grunt) {
var config = require('./config.json');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
less : {
files : ['front-end/less/**/*.less'],
tasks : ['newer:less','sync:css'/*,'run:deploy_less_files'*/]
},
// 1. Added new target to watch the directory in which the resultant
// .css files are saved. Set the `task` to `run:deploy_css_files`.
// The `nospawn` option must be set to true.
generatedCss : {
files : ['target/css/**/*'],
tasks : ['run:deploy_css_files'],
options: {
nospawn: true
}
}
},
less: {
development: {
options: {
paths: ['front-end/_builds/css'],
sourceMap : true,
},
files: [{
cwd: "front-end/less",
expand : true,
src : [ '**/*.less', '!_settings.less'],
dest : "front-end/_builds/css",
ext: ".css"
}]
},
},
sync : {
target: {},
css : {
expand: true,
flatten :true,
verbose: true,
cwd : "front-end/_builds/css/",
src : "**/*.css",
dest : "target/css/"
},
},
run : {
deploy_css_files : {// 2. Renamed target and added `exec` key. The
exec: '' // `exec` value is intentionally empty and will
} // be configured via the `watch` event listener.
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-sync');
grunt.loadNpmTasks('grunt-run');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-newer');
// 3. 'less' and 'sync' targets are aliased before the `watch`
// task to ensure the path defined in the `files` property of the
// `watch:generatedCss` task exists before `watch`ing.
grunt.registerTask('default', ['less', 'sync', 'watch']);
// 4. Listen for changes via the `watch:generatedCss` target only.
// Configures the `exec` property of the `run:deploy_css_files`
// target to `curl` the most recently created `.css` file.
grunt.event.on('watch', function(action, filepath, target) {
if (target === 'generatedCss') {
var cmd = 'curl -u ' + config.credentials.user + ':' +
config.credentials.pw + ' -T ' + filepath +
' http://localhost:8080/assets/less/';
grunt.config('run.deploy_css_files.exec', cmd);
}
});
}
Further explanation
Firstly, in the Gruntfile.js above, you'll notice that run:deploy_less_files alias has been omitted from your original watch.less.tasks array. Then the following changes were made:
Added a new target named generatedCss to the watch Task. Its files value specifies the path to the directory in which the resultant .css files are saved. The value in the task property array is set to run:deploy_css_files. The nospawn option is set to true.
Note As you mentioned the following in your question:
"Ideally, I'd like to just grab the css file from either my target or the _builds directory and upload it to my localhost,.."
I chose to name the target generatedCss and renamed the task to run deploy_css_files (instead of deploy_less_files) as this better reflects the actual intent.
The files that ultimately get uploaded via curl to your localhost will be from the target/css/ directory, simply because that's the directory we're watching for changes.
Replaced your original run task with the following instead:
run : {
deploy_css_files : {
exec: ''
}
}
Note The target has been renamed and the exec property added. Its value is intentionally empty as this will be configured via the watch event listener.
less and sync targets are aliased before the watch task of the default registered task. This ensures that, (when initially running grunt via your CLI), the path defined in the files property of the watch:generatedCss task exists before watching begins.
Finally, in the grunt.event.on('watch', ...) listener we listen for changes via the watch:generatedCss target only and configure the exec property of the run:deploy_css_files target to curl the most recently created .css file.
Running
When running the grunt command via your CLI any changes made to the .less files, (i.e. those residing in the /front-end/less directory), will trigger the tasks in the correct order (as per your listed points 1-4).
Caveat: I didn't actually test running the curl command, however the file path for the most recent generated .css file is assigned to the filepath variable in the grunt.event.on('watch', ...) listener, thus it can be referenced when configuring the run.deploy_css_files.exec task/target.
Note: you'll need to ensure the server supports POST requests for your curl command to succceed (i.e. it's not something like SimpleHTTPServer).

How can I use a static helper function(javascript) in SCSS to set the base url for images for different environments?

In my SCSS file I need to use different base urls for different app environments which will be prepended to the image name.
Example:
For production environment
background: url(/prod/image.png);
For development environment
background: url(/dev/image.png);
The helper function which I'm using in the rest of my app returns the base path of the static assets and it looks like this:
static imagePath() {
let imagesPath;
if (this.isProduction()) {
basePath = '/prod';
} else {
basePath = '/dev';
}
return basePath
}
How to achieve this?
Edit:*
I'm using extract-text-webpack-plugin which won't let me output multiple css files.
For example you can have 2 main files (dev.scss and prod.scss) that will look like:
// prod.scss
$basePath: '/prod';
#import "style.scss";
and same for dev.scss.
Otherwise you can use some placeholder for path prefix and substitute it with actual prefix on post-processing step. For example you can use this plugin for PostCSS.
UPDATE:
Following discussion in comments here is (untested) example of how webpack configuration may look like:
module.exports = {
// ....
module: {
rules: [
// ....
{
test: /\.scss$/,
use: {
loader: StringReplacePlugin.replace({
replacements: [
{
pattern: /{urlPrefix}/ig,
replacement: () => process.env.NODE_ENV !== 'production' ? '/dev' : '/prod',
}
]
}, 'sass-loader'),
}
},
// ....
],
},
plugins: [
new StringReplacePlugin(),
// ....
],
// ....
};

Grunt-replace : parametric json file

Goodmornig,
I'm using grunt-replace (https://github.com/outaTiME/grunt-replace) inside my gruntfile to replace some string in a html file by loading a json object from a json file.
I want to add some flexibility to this approach and i customized another task called 'setopts' that simply add some properties to the grunt.option that i use i the 'replace' task in the following way:
replace: {
common: {
options: {
patterns: [
{
json: '<%=grunt.option("locales")%>'
}
]
},
files: [
{expand: true, flatten: true, src: ['public/sites/<%=grunt.option("domain")%>/index.html'], dest: 'public/sites/<%=grunt.option("domain")%>/'},
]
}
}
Here my 'setopts' task :
grunt.registerTask('setopts', function (domain) {
locales = grunt.file.readJSON('src/locales/domain/myfile.json');
grunt.option('locales', locales);
grunt.option('domain', domain);
}
I run the following task :
grunt.registerTask('maintask', [ 'setopts:mydomain', 'replace:common']);
After some attempts i found that the 'files' property in the 'replace' task works fine but i get an error in the 'patterns' property :
Processing source...ERROR
Warning: Error while processing "public/sites/xxxxx/index.html" file. Use --force to continue.
What's going wrong with this?
Thanks for any comment!
I know I'm 1.5 years late, but maybe some other people might need the answer to this.
The way I made it work was by not using grunt.option. Instead, I used grunt.config.set.
replace: {
common: {
options: {
patterns: [
{
json: '<%= locales %>'
}
]
},
files: [
{expand: true, flatten: true, src: ['public/sites/<%= domain %>/index.html'], dest: 'public/sites/<%= domain %>/'},
]
}
}
Notice the way the locales variable is used as a value to the json property.
This is the setopts task:
grunt.registerTask('setopts', function (domain) {
locales = grunt.file.readJSON('src/locales/domain/myfile.json');
grunt.config.set('locales', locales);
grunt.config.set('domain', domain);
}
Hopefully it helps somebody :)
This question helped me find the answer Programmatically pass arguments to grunt task?

Categories