I want to have a gulp task in Visual Studio Code which watches all files in a folder called less with the extension .less. When found, a task must compile the less files to a folder called css on the same level as the less folder.
Current code:
gulp.task('less', function() {
gulp.src('less/*.less',{ cwd:'..' })
.pipe(less())
.pipe(gulp.dest( 'css' ), { cwd:'..' });
});
gulp.task('default', function() {
gulp.watch('./**/less/*.less', ['less']);
});
What I want:
x
y
less
style.less
css
style.css
What above code does:
x
y
less
style.less
css
y
less
style.css
I had this working when being specific in the path, but the problem is that i've less folders on multiple levels. How can I solve this?
I know this is bit old question, but felt worth sharing my answer.
gulp.task('app:less', [], function () {
return gulp.src(['./src/**/*.less'], { base: './src/' })
.pipe(less())
.pipe(gulp.dest('./src/'));
});
Setting base option to root folder with dest path to ./src/ worked for me.
Currently there is no way to do it. The only thing which could approach you to a solution is gulp-flatten. However, this requires to specify a fixed number of parents to include. In your case, where you have folders in different levels, you'd need to specify a different number for each case. So, the only option would be to modify the flatten code to support something like an excludeParents, which does the contrary that flatten, i.e exclude a fixed number of parents (in your case, 1).
Try this :
gulp.task('less', function() {
gulp.src(['**/*.less', *.less],{ cwd:'less' })
.pipe(less())
.pipe(gulp.dest('css'));
});
Related
Webpack bundle analyzer shows that icons from bootstrap-vue package are 535kb in size.
I don`t want to use them in a project, so I have been trying to exclude the package with a webpack IgnorePlugin.
According to example in documentation, I have tried to write this:
new webpack.IgnorePlugin({
resourceRegExp: /^icons(.*)$/,
contextRegExp: /^bootstrap-vue(.*)$/
})
but it didn`t work. The only thing I was able to reproduce, is to completely exclude bootstrap-vue lib via this constriction new webpack.IgnorePlugin(/bootstrap-vue/)
So how I can exclude only icons?
Here is the way to ignore the icons from bootstrap-vue:
new webpack.IgnorePlugin({
resourceRegExp: /\/icons\//,
contextRegExp: /bootstrap-vue/,
});
Next time if you are in doubt try to use checkResource function instead, it's easier to write and understand in comparison to regexp:
new webpack.IgnorePlugin({
checkResource (resource, context) {
if (context.includes('bootstrap-vue')) {
console.log(resource, ':::', context)
// check console to figure out how the resource is used
// update the function until it's satisfies your case
// then move to regexp if you wish
}
return false
},
})
But after doing this research it turned out that some components actually use some icons and icons in general are not as big as I expected. Using source of the bootstrap-vue had bigger impact on our bundle. So decided to stick with this approach instead
There's always an overlap with Navbar dropdown when more than one is clicked. It focuses and takes a few minutes to clear this becomes a problem because it causes clutter.
The configuration for this in the Vuepress docs is just to add navbar items and ariaLabel any know how I can stop this behaviour.
themeConfig: {
nav: [
{
text: 'Languages',
ariaLabel: 'Language Menu',
items: [
{ text: 'Chinese', link: '/language/chinese/' },
{ text: 'Japanese', link: '/language/japanese/' }
]
}
]
}
Here's an example
To answer your question one would need to address two distinct issues:
how do I run custom JavaSCript in VuePress?
how do I close any previously open dropdowns on click in my current VuePress theme, using JavaScript?
For the first problem there are several solutions (one of them being by using a custom component with code run in its mounted() hook, but this would require you to include that component in every page and make sure it doesn't run more than one time (since you want to bind events to elements).
I believe the cleanest way would be by adding a <script> to <head> which can be achieved by adding this to the head prop of your .vuepress/config.js export:
head: [
// ...existing stuff, if any,
['script', {}, `
(function() {
// your code here...
})();
`]
]
However, there are a few problems with the above solution. Firstly, it's going to be run as soon as it's parsed, and that's inside the <head> tag. Which means none of the contents of your page are rendered yet. And the second problem is you're in a template literal. You don't really want to be writing JavaScript code in a template literal. Ideally you should be able to put your code in a '.js' file and append it as a <script> tag.
In order to do that, you need to create a .vuepress/public/ folder, if you don't already have one. Place your .js file in there (I used test.js but feel free to name it as you like). Modify the above code to:
['script', {}, `
(function() {
var s = document.createElement('script');
s.src = './test.js';
var h = document.querySelector('head');
h.appendChild(s);
})();
`]
Change ./test.js to your file's name.
Now your file has clean JavaScript and the door is open. Your code executes in the window object context.
To answer the second part of your question, well..., it largely depends on the theme you are using. If you're using the default theme (which seems to be the case, from the SS you posted), this should work, if placed inside your .js file:
document.addEventListener('DOMContentLoaded', fixDropDowns);
function fixDropDowns() {
document.body.addEventListener('click', (ev) => {
const header = document.querySelector('header');
if (header) {
const dds = header.querySelectorAll('.dropdown-wrapper');
[...dds].forEach(el => el.classList.remove('open'));
const curr = ev.target.closest('.dropdown-wrapper');
if (curr) {
curr.classList.add('open');
}
}
})
}
But it's based on a close inspection of the generated markup.
Specifically on the fact the dropdowns have a class of .dropdown-wrapper and that they're opened by toggling class open on them. The above is just an example and will likely not work on other themes and might even stop working on the default theme in some future version.
I have a database table that contains a list of colour variables (example HEX colour code). My styles are compiled using Gulp and SASS.
When my Django app creates/updates a row in the database i need to build a new stylesheet based on the colours.
Somehow i need to get the colours from my server side app into a build process.
Record with colours added -> Gulp runs -> New colour variables are used within the stylesheet generation.
Any ideas how this could be done?
Thanks,
I solved this problem in a less than ideal way..
There is a module called gulp-preprocess which take a context array and replaces vars before the sass process runs..
For example:
SASS File
$body-background: '/* #echo body-background */';
body {
background: $body-background;
}
GULP
var data = {
'1': {
'body-background': '#f00',
},
'2': {
'body-background': '#ffffff',
}
}
gulp.task('scss', function () {
for (var partner_id in data) {
if (!data.hasOwnProperty(partner_id)) continue;
var partner_data = data[partner_id]
gulp.src('./static/scss/*.scss')
.pipe($.sourcemaps.init())
.pipe($.preprocess({context: partner_data}))
.pipe($.sass({
errLogToConsole: true,
style: 'compact'
})
.on('error', function (err) {
console.log('Error:', err);
this.emit('end');
}))
.pipe($.autoprefixer({cascade: false}))
.pipe($.cssnano())
.pipe($.sourcemaps.write('./maps'))
.pipe(gulp.dest('./static/css/'+ partner_id))
}
});
I came across this service https://www.grooveui.com, that lets you create multiple themes from your SASS files.
The only catch is you have to host your SASS files with them. Then you can create new themes and set variable values. I guess they are using database to store variables and generating multiple SASS files.
Could be worth a try.
I'm running into the following problem with requirejs and usemin:
I want to setup a multipage application, where I dynamically load modules that only contain page specific functionality (e.g. about -> about.js, home -> home.js). I could go ahead and pack everything in a single file, but that just leads to a bigger file size and overhead on functionality that isn't necessary on each site! (e.g. why would I need to load a carousel plugin on a page that doesn't have a carousel!)
I checked out the example https://github.com/requirejs/example-multipage-shim
That is in fact a great way to deal with it, until I bring usemin into the game. After revving the filenames the src path of each script tag is updated, but what about the dependencies?
<script src="scripts/vendor/1cdhj2.require.js"></script>
<script type="text/javascript">
require(['scripts/common'], function (common) {
require(['app'], function(App) {
App.initialize();
});
});
</script>
In that case, require.js got replaced by the revved file 1cdhj2.require.js. Great!
But the required modules "common" and "app" no longer work since common became 4jsh3b.common.js and app became 23jda3.app.js!
What can I do about this? Thanks for your help!
(Also using Yeoman, btw)
It's a tricky problem and I'm sure somebody else fixed in in a more elegant way, but the following works for me.
I might publish this as a grunt plugin once it's a little more robust.
Taken from my Gruntfile:
"regex-replace": {
rjsmodules: { // we'll build on this configuration later, inside the 'userevd-rjsmodules' task
src: ['build/**/*.js'],
actions: []
}
},
grunt.registerTask('userevd-rjsmodules', 'Make sure RequireJS modules are loaded by their revved module name', function() {
// scheduled search n replace actions
var actions = grunt.config("regex-replace").rjsmodules.actions;
// action object
var o = {
search: '',
replace: '', //<%= grunt.filerev.summary["build/js/app/detailsController.js"] %>
flags: 'g'
};
// read the requirejs config and look for optimized modules
var modules = grunt.config("requirejs.compile.options.modules");
var baseDir = grunt.config("requirejs.compile.options.dir");
var i, mod;
for (i in modules) {
mod = modules[i].name;
revvedMod = grunt.filerev.summary[baseDir + "/" + mod + ".js"];
revvedMod = revvedMod.replace('.js', '').replace(baseDir+'/','');
o.name = mod;
o.search = "'"+mod+"'";
// use the moduleid, and the grunt.filerev.summary object to find the revved file on disk
o.replace = "'"+revvedMod+"'";
// update the require(["xxx/yyy"]) declarations by scheduling a search/replace action
actions.push(o);
}
grunt.config.set('regex-replace.rjsmodules.actions', actions);
grunt.log.writeln('%j', grunt.config("regex-replace.rjsmodules"));
grunt.task.run("regex-replace:rjsmodules");
}),
You can also use requirejs' map config to specify a mapping between your original module and your revved one.
Filerev outputs a summary object containing a mapping of all the modules that were versioned and their original names. Use grunt file write feature to write a file in AMD way with the contents being the summary object:
// Default task(s).
grunt.registerTask('default', ['uglify', 'filerev', 'writeSummary']);
grunt.registerTask('writeSummary', 'Writes the summary output of filerev task to a file', function() {
grunt.file.write('filerevSummary.js', 'define([], function(){ return ' + JSON.stringify(grunt.filerev.summary) + '; })');
})
and use this file in your require config so that the new revved modules are used instead of old ones:
require(['../filerevSummary'], function(fileRev) {
var filerevMap = {};
for (var key in fileRev) {
var moduleID = key.split('/').pop().replace('.js', '');
var revvedModule = '../' + fileRev[key].replace('.js', '');
filerevMap[moduleID] = revvedModule;
}
require.config({
map: {
'*': filerevMap
}
});
The filerevMap object that I created above is specific to my folder structure. You can tweak it as per yours. It just loops through the filerev summary and makes sure the keys are modified as per your module names and values as per your folder structure.
I saw there is somes questions related to mine (like this interesting one), but what I wonders is how to do it correctly, and I couldn't find it via the others questions or the RequireJS documentation.
I'm working on a quite heavy web application that will run in only one html page.
Before RequireJS, I used to do a lot of JS modules with public methods and connecting them via the on event on the Dom READY method, like this :
var DataList = function () {
this.base = arguments[0];
this.onUpdate = function (event) { ... }
}
$(function () {
var dataList = {}; DataList.apply(dataList, [$('#content')]);
$('table.main', dataList.base).on ('update', dataList.onUpdate);
});
With RequireJS, I can easily see that I can split DataList and all others classes like this on individual files, but what about the $(function () {}); part?
Can I still keep it this way, but instead of the DOM ready function of jQuery, I put the events on the main function() of the RequireJS, when my primary libs are loaded?
Or do I have to change the way I create JS "classes", to include a init function maybe, that will be called when I do a, for example :
require(['Datalist'], function(dataList) {
dataList.init($('#content'));
});
What annoys me the most is that since I have only one html file, I'm afraid the require() will have to load a huge list of files, I'd prefer it to load just libs that, them, would load sub libs required to work.
I don't know, the way of thinking with RequireJS lost me a bit :/
How would you do?
"Can I still keep it this way, but instead of the DOM ready function of jQuery, I put the events on the main function() of the RequireJS, when my primary libs are loaded?"
If you separate the functions or 'classes' into modules then you can use the RequireJS domReady function:
require(['module1'], function(module1) {
domReady(function(){
// Some code here ftw
})
});
The benefit here is the domReady function will allow downloading of the modules instantly but won't execute them until your DOM is ready to go.
"Or do I have to change the way I create JS "classes", to include a init function maybe, that will be called when I do a, for example"
You won't need to change the way you interact with your code this way, but you can probably improve it. In your example I would make DataList a module:
define(function(require) {
var $ = require('jquery');
var DataList = function () {
this.base = arguments[0];
};
DataList.prototype.onUpdate = function() {
};
return DataList;
});
require(['data-list'], function(DataList) {
var data = {};
// Call DataList with new and you won't need to set the context with apply
// otherwise it can be used exactly as your example
new DataList(data);
});
"What annoys me the most is that since I have only one html file, I'm afraid the require() will have to load a huge list of files, I'd prefer it to load just libs that, them, would load sub libs required to work."
Make your code as modular as you want/can and then use the optimiser to package it into one JS file.