Gulp doesn't create folder? - javascript

When I minified my css, I was left with an incorrect path to the fonts from various libraries. So, I created a task to move the fonts from my bower_components/ folder to dist/public/fonts:
gulp.task('doit', function() {
gulp.src(["public/bower_components/bootstrap/dist/fonts/*", "public/bower_components/font-awesome/fonts/*"])
.pipe(gulp.dest("dist/public/fonts"));
});
Basically that should throw any fonts I need into a generic fonts folder, which my minified css should now be able to access.
But after I run it, dist/public/fonts doesn't exist. Why not?

I don't fully understand the paths you're src-ing (public/bower_components?), but I believe you'll want to use the base option for gulp.src.
Because these two globs will have different bases, I'd suggest breaking it into two separate tasks, and building a third to aggregate them into a single. Otherwise you'll need to get into merging streams or the addSrc plugin.
gulp.task('copy:fonts:bootstrap', function () {
return gulp.src(
[
'public/bower_components/bootstrap/dist/fonts/**/*'
],
{
base: 'public/bower_components/bootstrap/dist/fonts'
}
)
.pipe(gulp.dest('dist/public/fonts'));
});
gulp.task('copy:fonts:fontawesome', function () {
return gulp.src(
[
'public/bower_components/font-awesome/fonts/**/*'
],
{
base: 'public/bower_components/font-awesome/fonts'
}
)
.pipe(gulp.dest('dist/public/fonts'));
});
gulp.task('copy:fonts', ['copy:fonts:bootstrap', 'copy:fonts:fontawesome']);

According to this article, specify your src like this:
gulp.src(['src/js/**/*.js'], { base: 'src' })
.pipe(foo())
.pipe(gulp.dest("./public/"));
and it will auto create the destination directories for you. In this case, the 'js' folder will be created in public if it doesnt exist already.

Related

Can't resolve css url from webpack asset librarymodule

I was able to output an assets library and many other libraries that work as remote federated modules and as deep import libraries in case I am not connecting to a remote or I am not using webpack in the consumer end.
The issue is now that all my assets exports a module, that either have the raw data as uri or the string that points to the right asset. Eg: the bird.svg is outputed to dust with it's hash plus the modules that resolves to the file bird-[hash].svg.
The above is great from javascript but not so much for css. Now I can't rewrite the url() to point to the right remote path which would be sg like:
//since I don't know when the assets will change names I can't refer to it directly. So I would need to first read the string from the bird.js module. Append the publicPath and then rewrite the url.
.someClass {
background-image: url('/assets/bird.js')
}
//the above won't work for obvious reasons.
Só, the question is how can I solve this? Or is there any loader for this? I checked the resolve url loader but it does not seem to be what need.
Ok I resolved this issue, by passing additional data as variable to sass-loader. That way I can evaluate the actual name of the files, and put it as a sass map before and handle it from sass.
//I am using glob to return an object with all the assets.
//This can probably be automated better. That would be an easier way.
//But this way works for me in all 3 scenarios, node, browser and federated module.
//Also has caching ootb for the assets.
const assetsPaths = {
...glob.sync('../assets/dist/img/**.node.js').reduce(function (obj, el) {
obj['img/' + path.parse(el).name] = '../../assets/dist/' + require(el).default;
return obj
}, {}), ...glob.sync('../assets/dist/fonts/**.node.js').reduce(function (obj, el) {
obj['fonts/' + path.parse(el).name] = '../../assets/dist/' + require(el).default;
return obj
}, {})
};
//...
{
loader: 'sass-loader',
options: {
additionalData: "$assets: '" + assetsMap + "';",
sourceMap: true,
sassOptions: {
outputStyle: "compressed",
},
}
},
//...
you also need to disable url rewriting
{
loader: 'css-loader',
options: {
url: false,
}
},
then you can use assets map in your sass files:
#font-face {
font-family: 'Some Font';
src: local('Some Font');
src: url("#{map-get($assets, SomeFont)}");
}
You will need probably have your project setup sort like a mono repo and you also need to build those assets library with two bundles.
One for node so you can use the string path to your actual assets when bundling you sass/whatever.
And another for normally loading it from the browser.
update:
Instead of doing all this I just used the manifest generated from 'webpack-manifest-plugin' to build the $assets map to be used in sass.
const assetsManifest = JSON.parse(fs.readFileSync('../assets/dist/manifest.json'));
const assetsMapFn = asset => `'${asset[0]}':'${asset[1]}'`;
const assetsMap = `(
${Object.entries(assetsManifest).map(assetsMapFn).join(',')}
); `;
If anyone knows a better way to do this please reply or comment.

Grunt build script that reads xml file to determine which files are copied

copy: {
build: {
cwd: 'app',
src: ['**', '!**/vendors/**', '!**src/js/*.js',],
dest: 'dist',
expand: true
}
}
I am using grunt build scripts to build a distribution folder for the completed product. However, its not 100% automatic and dynamic. For example, I have a folder of xml content files. Yet, I don't use them all. Right now, the whole folder is copied over to the build version. Manually I have to go in and delete the xml files I don't want in the build version then run it. Or I could go into the grunt file and and tell it to ignore those files.
The problem is that I don't want to do that every time. A theoretical idea I had would be to have an xml file where I define elements to represent certain other files.
<bootstrap>true</bootstrap>
<extraContent>false</extraContent>
This would say that the file correlated to bootstrap and extraContent should or shouldn't be ignored in the build. I am trying to figure out if you could do this in grunt.
something like the following is how I see the logic playing out...
var bootstrap = $(xml).find("bootstrap").text()
if(bootstrap == "false"){
var url = src/bootstrap.css
//Here add the correlated filepath defined above to be ignored
}
The problem is not only writing this so grunt knows what it is, but also combining that logic with the actual "copy:{}" script I showed above
If you want to include/exclude files based on their contents you can use filter function for this. Examples can be found in the official documentation: https://gruntjs.com/configuring-tasks#custom-filter-function.
The filter property can help you target files with a greater level of detail.
In your case this could be something like this:
copy: {
build: {
cwd: 'app',
src: ['**', '!**/vendors/**', '!**src/js/*.js',],
dest: 'dist',
expand: true,
// this filter function will copy xml files only when `bootstrap` is set to 'true'
filter: filepath => {
if (require('path').extname(filepath) !== 'xml')
return true;
const xml = require('fs').readFileSync(filepath, 'utf8');
const json = require('xml2json').toJson(xml);
return json.bootstrap === 'true';
}
}
}
You can then use the process function to copy only certain contents from specific files: https://github.com/gruntjs/grunt-contrib-copy#process
This option is passed to grunt.file.copy as an advanced way to control the file contents that are copied.

Browserify adding unwanted directories

Setting up gulp for the first time. I've got it correctly compiling the files, it's just sticking them in the wrong place, and I can't quite figure out what to change to get it right.
After they compile, I have it adding the .conveyor.js suffix and then I want it to place them in the /scripts directory. But it's placing them in /scripts/src/js/ — it's adding a couple subdirectories. The raw dev files themselves are in src/js/ directories in a separate location, but I don't want that to carry over. Here's my gulp setup:
module.exports = function() {
var files = [
'./src/js/dashboard.js',
'./src/js/pages.js',
'./src/js/poll.js'
];
var tasks = files.map(function(entry) {
return browserify({
entries: [entry],
paths: ['./node_modules', './src/js/']
})
.bundle()
.pipe(source(entry))
.pipe(rename({
extname: '.conveyor.js'
}))
.pipe(gulp.dest('../scripts/'));
});
return es.merge.apply(null, tasks);
};
The way I understand it, "files" are all of the files it looks for to compile. "paths" allow you to specify directories that your require statements can be relative to so you don't have to do a bunch of period-forwardslashing. and then "dest" is where you want the files to end up. But I'm clearly misunderstanding something.
The offender is here
.pipe(source(entry))
entry is set to the exact path you are using for the files path. Hence the duplication.
source() in this isn't the source of the file, but ends up being the file that gets created.
You would want to modify the object to provide just the file name as the entry and the source path is separated. Also, you can drop the rename method, I think.

Two Different WebApps with one Source Code

Hope someone can help me figure out this.
I have 3 products that have almost the same interface, lets say Product A, B and C
What I want to do, if possible(through Gulp/Grunt/Other), is to create one source code and when building the final app, it will carry over to the dist folder the part for Produtc A, B C.
Example:
app/
js/
assets/
views/
dist/
ProdA/
ProdB/
ProdC/
Creating the build isn't the hard part, but how can I make my code so I can consume consume different API for each product.
Example:
Product A, B and C have status pages, A have (3 fields), B have all field from A (plus one) and C have fields completely different.
Do you guys have tips/tricks/guides so I can accomplish a similar task and reduce my code re-use?
Some Thoughts and Options
Your question seems to leave it to interpretation. Too many open ended answers possible, and many great answers will be provided. However, based on what I think you are doing, here are some options:
Use an external config file, and use globbing patterns for each, and exclude what you don't want.
Create a gulp task that copies some source files and moves them to your dist/a, dist/b, etc.
Turn your reusable code into a node_module and 'require' it in each apps src.
Turn your reusable code into a git submodule and use it as a dependency for each app. Works well with the previous point.
A Gulp Task to move files and folders
For exactly what you asked, all sharing one repo (I do highly recommend separate repos though to simplify the tasks), here is a gulp task you can use to move files around. It's very simple.
This example / suggestion will have two parts for convenience. The task, and a config section to manage it. You can either use it in the gulpfile, or as an external file which may be easier to manage if you are using the same gulpfile for three projects.
You could also use merge-stream to do the same task to multiple src & dest:
npm install --save-dev merge-stream
gulpfile.js
// =========================================================
// Projects: Project A, Project B, Project C
// info:
//
// =========================================================
// ------------------------------------------------ Requires
var gulp = require('gulp'),
merge = require('merge-stream');
// -------------------------------------------------- Config
var config = {
// These are some examples
reusable: [
'./src/reusableCode/scripts/**/*.js',
'./src/reusableCode/styles/**/*.css
],
productA: {
src: [ ], // Add product A src
opts: { }, // Add product A options for gulp tasks,
dest: './dist/A'
},
productB: {
src: [ ], // Add product B src
opts: { }, // Add product B options for gulp tasks,
dest: './dist/B'
},
productC: {
src: [ ], // Add product C src
opts: { }, // Add product C options for gulp tasks,
dest: './dist/C'
},
}
// --------------------------------------------------- Tasks
// ...
gulp.task('moveSrc', function(){
var prodA = gulp.src( config.reusable )
.pipe( gulp.dest( './dist/A' ) );
var prodB = gulp.src( config.reusable )
.pipe( gulp.dest( './dist/B' ) );
var prodC = gulp.src( config.reusable )
.pipe( gulp.dest( './dist/C' ) );
return merge( prodA, prodB, prodC);
});
// A task to move folders and files without `merge-stream`
// gulp.task( 'moveSingleStream', function() {
// gulp.src takes the src into a stream, and output the stream
// just by using gulp.dest . This moves files and folders around
gulp.src( config.reusable )
.pipe( './dist' );
});
// --------------------------------------------------- Build
gulp.task( 'build', [ 'moveSrc', 'otherTask1', 'otherTask2' ] );
You could also skip the reasuable array in config in this example, and just add what you want to move in each products src array. Whatever works.
Now that being said, I would suggest separate repo's and using that reusable code as node modules, but you can use merge-stream to simplify the process of using the same tasks to do multiple things. I hope this helps.
Assuming I understand your question, what you want is a basic service that has modifications by the product type. If it is the case, you can use angular's service decorator, this enables you to take an existing service and add to it functionality, either by defining new methods or wrapping the behavior of existing methods. If this works for you, have each product decorate the base service according to its needs.
There are many examples of decorations, for example this one.

Custom source processing during optimization using r.js and requirejs

I wanted to know if there is any way I can customize how r.js processes the source code of javascript (or other) files during the merging/optimization of a project that uses require.js.
I need to apply some custom transformations, as for example handling some java-like annotations.
I'm looking for something similar to what is possible with browserify using the b.use().
Found the solution. Is it actually possible using the "onBuildWrite" configuration parameter , and specifying a callback that is executed before each module is serialized.
Something like:
var config = {
baseUrl: 'src',
onBuildWrite: function( name, path, contents ) {
//Additional processing
return contents;
},
modules: [{
name: 'main'
}],
};
requirejs.optimize( config, function(results) {});

Categories