Creating svg sprites using grunt module - javascript

I'm new to grunt and node js. I'm facing issues in creating svg sprites using grunt-svg-sprite module. I have used grunt-svg-sprite module to create svg sprite image. I have installed the grunt-svg-sprite module using the following command.
npm install grunt-svg-sprite --save-dev
I enabled the plugin in my grunt.js file using the line below.
grunt.loadNpmTasks('grunt-svg-sprite');
And my plugin configuration is as follows
svg_sprite : {
basic : {
// Target basics
expand : true,
cwd : 'images/svg-logo/',
src : 'images/svg-logo/*.svg',
dest : 'out/',
// Target options
options : {
mode : {
css : { // Activate the «css» mode
render : {
css : true // Activate CSS output (with default options)
}
}
}
}
}
},
My folder structure is given below
Project_folder
├───css
├───Images
│ └───svg-logo
├───GruntFile.js
├───html
├───node_modules
├───include
├───package.json
When i run the following command, i get the success message, but there is no folder has created.

Everything is ok here. src should be specify only the file there.
Try with this one.
svg_sprite : {
basic : {
expand : true,
cwd : 'images/svg-logo',
src : ['**/*.svg'],
dest : 'out',
options : {
mode : {
css : {
render : {
css : true
},
},
},
},
},
},

Related

Nx React - Assets can't be resolved

I'm working on a nx monorepo that has a few library and 2 apps.
File Structures
apps
\--api
\--funnel ( react with webpack )
\--api-e2e
\--funnel-e2e
libs
\--funnel
\----pages
\--shared
\----assets
\-------src
\--------lib
\----------'some .tsx assets' ( lottie files )
\--------assets
\----------images
\-------------**/*.(png|webp|gif|svg) ( all others assets )
What's expected
In my libraries and in my app, I'd like to use the assets as such:
import imageName from '/assets/images/<some-image-folder>/<some-image-name>.<ext>';
For all svg, png, jpeg, etc...
for svgs: import { ReactComponent from imageName } from '/assets/images/<some-image-folder>/<some-image-name>.svg';
Issue
My actual issues is that when i'm building the funnel app nx run funnel:build --verbose
my assets seems to be loaded into the cache but every assets return a : Module not found: Error: Can't resolve '/assets/images/<some-image-folder>/<some-image-name>.<ext>' from '<whatever-lib>/<main-app>'
Yes i use /assets/images As i'm using angular functionaility to "serve" the assets to /assets/images
What is my config
#NX Report
Node : 16.16.0 OS : darwin x64 npm : 9.2.0
nx : 15.6.0 #nrwl/angular : Not Found #nrwl/cypress : 15.6.0 #nrwl/detox : Not Found #nrwl/devkit : 15.6.0 #nrwl/esbuild : Not Found #nrwl/eslint-plugin-nx : 15.6.0 #nrwl/expo : Not Found #nrwl/express : 15.6.3 #nrwl/jest : 15.6.0 #nrwl/js : 15.6.0 #nrwl/linter : 15.6.0 #nrwl/nest : Not Found #nrwl/next : Not Found #nrwl/node : 15.6.3 #nrwl/nx-cloud : 15.0.3 #nrwl/nx-plugin : Not Found #nrwl/react : 15.6.0 #nrwl/react-native : Not Found #nrwl/rollup : Not Found #nrwl/schematics : Not Found #nrwl/storybook : Not Found #nrwl/web : Not Found #nrwl/webpack : 15.6.3 #nrwl/workspace : 15.6.0 #nrwl/vite : Not Found typescript : 4.8.4
#app/funnel/project.json
My assets are imported through the main app as i don't build any of the sub-lib here's the selector :
{
"input": "libs/shared/assets/src/assets/images",
"glob": "**/*",
"output": "assets/images"
}
#app/funnel/webpack.config.js
Couldn't import the whole code due to StackOverflow error but, in simple terms i added svgr support, file-loader & url-loader
module: {
rules: [
{
test: /\.(webp|png|gif|jpe?g)$/i
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
},
},
{
test: /\.svg$/,
use: [
'#svgr/webpack',
'url-loader'
]
}
],
}
Explanation of what I've tried so far
#1rst attempt
I used the angular functionality to import assets on build such as shown on the top config with the selector.
#2nd attempt
I used copy-webpack-plugin to copy static assets to '/assets/' without success
#3rd attempt
I added a path to the main tsconfig.base.json "#myapp/assets/*" : ["libs/shared/assets/src/assets/**/*"]
and tried to serve the assets as such : "#myapp/assets//."
#4rth attempt
The solution that works but isn't optimized for my workflow is to put each asset next to its dependencies...
This is disgusting as I need to duplicate assets, which are subject to a lot of changes.
Please help.
Here's the small-sized test repo : https://github.com/Sosumappu/assets-monorepo-test
Regarding your project it is not an asset pb, but an issue with loading svg images
I managed to load it .
At first upgrade your nx project from nx 15.6.0 to nx 15.6.3 :
npx nx migrate latest
You made a mistake, replace apple-pay.svg with applepay.svg in your project
change the color of your svg file to red, we can not see it (white on white background).
edit webpack.config.js as follow :
const { composePlugins, withNx } = require('#nrwl/webpack');
const { withReact } = require('#nrwl/react');
// Nx plugins for webpack.
module.exports = composePlugins(
withNx({
nx: {
svgr: true,
},
}),
withReact({ svgr: true }),
(config) => {
return config;
}
);
shared-ui.tsx
import styled from 'styled-components';
//Static Import
import Logo from '#github-test/shared/assets';
export const ApplePayIcon = () => {
return <Logo />;
};
libs/shared/assets/src/index.ts :
import Logo from '-!#svgr/webpack!./assets/images/applepay.svg';
export default Logo;
here you can console.log(Logo), you will see it is creating a react component

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 to enable Stylus url() rewrites

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
}
}
}
});

Require.js Error: Load timeout for modules: backbone,jquerymobile

I am trying to use r.js to optimize my code but I keep running to this error:
Tracing dependencies for: init
Error: Load timeout for modules: backbone,jquerymobile
The command I am running is this:
$ java -classpath /Users/dixond/build-tools/rhino1_7R4/js.jar:/Users/dixond/build-tools/closurecompiler/compiler.jar org.mozilla.javascript.tools.shell.Main /Users/dixond/build-tools/r.js/dist/r.js -o /Users/dixond/Sites/omm_mobile/js/build.js
My build.js file looks like this:
( {
//appDir: "some/path/",
baseUrl : ".",
mainConfigFile : 'init.js',
paths : {
jquery : 'libs/jquery-1.8.3.min',
backbone : 'libs/backbone.0.9.9',
underscore : 'libs/underscore-1.4.3',
json2 : 'libs/json2',
jquerymobile : 'libs/jquery.mobile-1.2.0.min'
},
packages : [],
shim : {
jquery : {
exports : 'jQuery'
},
jquerymobile : {
deps : ['jquery'],
exports : 'jQuery.mobile'
},
underscore : {
exports : '_'
},
backbone : {
deps : ['jquerymobile', 'jquery', 'underscore'],
exports : 'Backbone'
}
},
keepBuildDir : true,
locale : "en-us",
optimize : "closure",
skipDirOptimize : false,
generateSourceMaps : false,
normalizeDirDefines : "skip",
uglify : {
toplevel : true,
ascii_only : true,
beautify : true,
max_line_length : 1000,
defines : {
DEBUG : ['name', 'false']
},
no_mangle : true
},
uglify2 : {},
closure : {
CompilerOptions : {},
CompilationLevel : 'SIMPLE_OPTIMIZATIONS',
loggingLevel : 'WARNING'
},
cssImportIgnore : null,
inlineText : true,
useStrict : false,
pragmas : {
fooExclude : true
},
pragmasOnSave : {
//Just an example
excludeCoffeeScript : true
},
has : {
'function-bind' : true,
'string-trim' : false
},
hasOnSave : {
'function-bind' : true,
'string-trim' : false
},
//namespace: 'foo',
skipPragmas : false,
skipModuleInsertion : false,
optimizeAllPluginResources : false,
findNestedDependencies : false,
removeCombined : false,
name : "init",
out : "main-built.js",
wrap : {
start : "(function() {",
end : "}());"
},
preserveLicenseComments : true,
logLevel : 0,
cjsTranslate : true,
useSourceUrl : true
})
And my init.js looks like this:
requirejs.config({
//libraries
paths: {
jquery: 'libs/jquery-1.8.3.min',
backbone: 'libs/backbone.0.9.9',
underscore: 'libs/underscore-1.4.3',
json2 : 'libs/json2',
jquerymobile: 'libs/jquery.mobile-1.2.0.min'
},
//shimming enables loading non-AMD modules
//define dependencies and an export object
shim: {
jquerymobile: {
deps: ['jquery'],
exports: 'jQuery.mobile'
},
underscore: {
exports: '_'
},
backbone: {
deps: ['jquerymobile', 'jquery', 'underscore', 'json2'],
exports: 'Backbone'
}
}
});
requirejs(["backbone",], function(Backbone) {
//Execute code here
});
What am I doing wrong in this build process?
Require.js has a Config option called waitSeconds. This may help.
RequireJS waitSeconds
Here's an example where waitSeconds is used:
requirejs.config({
baseUrl: "scripts",
enforceDefine: true,
urlArgs: "bust=" + (new Date()).getTime(),
waitSeconds: 200,
paths: {
"jquery": "libs/jquery-1.8.3",
"underscore": "libs/underscore",
"backbone": "libs/backbone"
},
shim: {
"underscore": {
deps: [],
exports: "_"
},
"backbone": {
deps: ["jquery", "underscore"],
exports: "Backbone"
},
}
});
define(["jquery", "underscore", "backbone"],
function ($, _, Backbone) {
console.log("Test output");
console.log("$: " + typeof $);
console.log("_: " + typeof _);
console.log("Backbone: " + typeof Backbone);
}
);
The Error
I recently had a very similar issue with an angularJS project using requireJS.
I'm using Chrome canary build (Version 34.0.1801.0 canary) but also had a stable version installed (Version 32.0.1700.77) showing the exact same issue when loading the app with Developer console open:
Uncaught Error: Load timeout for modules
The developer console is key here since I didn't get the error when the console wasn't open. I tried resetting all chrome settings, uninstalling any plugin, ... nothing helped so far.
The Solution
The big pointer was a Google group discussion (see resources below) about the waitSeconds config option. Setting that to 0 solved my issue. I wouldn't check this in since this just sets the timeout to infinite. But as a fix during development this is just fine. Example config:
<script src="scripts/require.js"></script>
<script>
require.config({
baseUrl: "/another/path",
paths: {
"some": "some/v1.0"
},
waitSeconds: 0
});
require( ["some/module", "my/module", "a.js", "b.js"],
function(someModule, myModule) {
//This function will be called when all the dependencies
//listed above are loaded. Note that this function could
//be called before the page is loaded.
//This callback is optional.
}
);
</script>
Most common other causes for this error are:
errors in modules
wrong paths in configuration (check paths and baseUrl option)
double entry in config
More Resources
Troubleshooting page from requireJS: http://requirejs.org/docs/errors.html#timeout point 2, 3 and 4 can be of interest.
Similar SO question: Ripple - Uncaught Error: Load timeout for modules: app http://requirejs.org/docs/errors.html#timeout
A related Google groups discussion: https://groups.google.com/forum/#!topic/requirejs/70HQXxNylYg
In case others have this issue and still struggling with it (like I was), this problem can also arise from circular dependencies, e.g. A depends on B, and B depends on A.
The RequireJS docs don't mention that circular dependencies can cause the "Load timeout" error, but I've now observed it for two different circular dependencies.
Default value for waitSeconds = 7 (7 seconds)
If set to 0, timeout is completely disabled.
src: http://requirejs.org/docs/api.html
The reason for the issue is that Require.js runs into the timeout since the project might have dependencies to large libraries. The default timeout is 7 seconds. Increasing the value for this config option (called waitSeconds) solves it of course but it is not the right approach.
Correct approach would be to improve the page loading time. One of the best technics to speed up a page loading is minification - the process of compressing the code. There are some good tools for minification like r.js or webpack.
I only get this error when running tests on Mobile Safari 6.0.0 (iOS 6.1.4). waitSeconds: 0 has given me a successful build for now. I'll update if my build fails on this again
TLDR:
Requiring the same file twice with two valid different names, possibly two of the following:
absolute path: '/path/to/file.js'
relative path: './path/to/file.js'
as a module: 'path/to/file'
as a module on main paths config:
paths: {
'my/module/file' : '/path/to/file'
}
Recently had this same issue. I did change some require paths in bulk so I knew the issue was about that.
I could clearly see on both server side logs and network debugging tab the file being served in less than a second. It was not a real timeout issue.
I tried to use xrayrequire as suggested to find any circular dependency without success. I looked for requires of the conflicting file and found out I was requiring it twice with different names.

Categories