recreating gulp config on webpack - javascript

Right now really need help to understand webpack, although I'm trying so much, im still not understand how I can use webpack as a task runner rather than just module bundler. This is a learning process, so please lets not discuss of why gulp/webpack is better than other for this kind of job.
You see the code is actually pretty simple, the idea is to crawl every htmlfile based on a template that injected with a variable from css and js with the same name. This gulpfile is what I use in order to create Polymerjs Html File.
Is there any way I could convert this into Webpack specific build tools? Where should I put the information to crawl the folder in the webpack? Should I put it into index.js?
I understand the concept of using a specific entry files for Webpack, but when facing this kind of usecase, what should I do?
gulp.task('templates', function() {
// crawl folder pathToFolder
readdir(pathToFolder, ['*.scss', '*.js', '*.json'], function(err, files) {
// loop every file founds
files.forEach(function(file) {
let data = file.substr(10);
// make sure the path is correct when used on windows device.
data = data.replace(String.fromCharCode(92), String.fromCharCode(47));
let index = data.lastIndexOf('/');
let path = data.substr(0, index);
let scss = file.substr(0, file.lastIndexOf('.')) + '.scss';
let js = file.substr(0, file.lastIndexOf('.')) + '.js';
let json = file.substr(0, file.lastIndexOf('.')) + '.json';
// process all files into their respective loader and squash it into one variable to use on the template.
let process = {
css: '',
form: '',
js: '',
json: '',
};
if (fs.existsSync(scss)) {
process = Object.assign(process, {
css: sass.compiler.renderSync({
file: scss,
}).css,
});
}
if (fs.existsSync(js)) {
process = Object.assign(process, {
js: fs.readFileSync(js, 'utf8'),
});
}
if (fs.existsSync(json)) {
let x = gulp.src('./ramen-renderer.html')
.pipe(template({
json: json,
}));
process = Object.assign(process, {
json: x,
});
// jsonProcess = Object.assign(jsonProcess, {json: fs.readFileSync(json, "utf8")});
}
// render the final html path with gulp-template
return gulp.src(file)
.pipe(template(process))
.pipe(gulp.dest('src/' + path));
});
});
});

webpack is not a task runner but a module bundler. That means you need another way to run tasks. The most common way to do this is to use NPM for this. You define your tasks in your package.json under the scripts section.

Related

Is there any way to get a list of files in a directory into a variable when using webpack?

When creating a browser app, there doesn't seem to be any way to get a list of files in a particular location using javascript. In Nodejs this is easily done using fs.
Basically I have a directory called images/, and I want to manipulate a list of all the files as a javascript variable without having to manually create the list of files. I thought that since webpack bundles all of the files that there might be some way to generate the list as a JSON file (or an alternative) which could be read in with javascript -- though I haven't found any way to do that yet.
What is the best way to do this?
I was able to solve this by creating a plugin:
src/plugins/FileLister.js:
const fs = require('fs');
class FileLister {
constructor(options) {
if (!options || !options.path || !options.outputFile) {
const msg = "Please specify the path and outputFile options.";
throw new Error(msg);
}
this.options = options
}
apply(compiler) {
compiler.hooks.done.tap({name: 'FileLister'}, () => {
const files = fs.readdirSync(this.options.path)
fs.writeFileSync(this.options.outputFile, JSON.stringify(files));
})
}
}
module.exports = FileLister;
Then in my webpackage.config.js:
import:
const FileLister = require('./src/plugins/FileLister.js')
plugins section:
new FileeLister({
path: path.resolve(__dirname, 'src/important_files/'),
outputFile: path.resolve(__dirname, 'dist/important_files.json')
}),
This creates a file called important_files.json in the dist directory containing a list of the files in src/important_files/.

How can I achieve this using gulp?

I am enumerating the subdirectories in a directory. For each sub directory I would like to apply a number of gulp activities like less compilation, and then create an output file specific to that subdirectory.
I would like the gulp process to continue, as further transformation steps need to be performed later.
Can someone help me understand how I can create these files half way through the "gulp pipeline"?
This seems quite interesting to achieve and gulp has no limitations at all.
I will give you detailed example how I have managed to accomplish such a task a while ago.
Let assume that you have directoryA. Subdirectories childA, childB and childC are contained into directoryA. So basically your tree structure looks like:
directoryA
--childA
--childB
--childC
I am always looking for a flexible solutions so I would suggest to include a JSON file in each subdirectory naming the tasks you would like to running. Using fs you can access these files. You can also use run-sequence to execute gulp tasks synchronously.
For demo purposes place a file named manifest.json inside childA subdirectory.
Manifest.json contains the following declarations:
{
"filesToProccess" : ["./childA/*.js", "./childB/*.js"],
"tasksToRun" :["taskA", "taskB"]
}
Finally gulpfile would like this:
'use strict';
//dependencies declared into package.json
//install them using npm
var gulp = require('gulp'),
fs = require('fs'),
runSequence = require('run-sequence'),
path = require('path');
//these two array will keep the actions you have included into manifest file.
var filesHolder = [], tasksHolder = [];
gulp.task('taskA', function () {
return gulp.src(filesHolder)
.pipe(whatever)
.pipe(gulp.dest('whatever')); //chailed actions
});
gulp.task('taskB', function () {
return gulp.src(filesHolder)
.pipe(whatever)
.pipe(gulp.dest('whatever'));
});
//a simple utility function to read all subdirectories of directoryA
function getDirectories(srcpath) {
return fs.readdirSync(srcpath).filter(function(file) {
return fs.statSync(path.join(srcpath, file)).isDirectory();
});
}
//finally insert the default gulp task
gulp.task('default', function(){
var manifest;
//map directory's A subdirectories
var availableDirs = getDirectories("./directoryA");
//finally loop the available subdirectories, load each manifest file and
availableDirs.forEach(function(subdir) {
manifest = require("./directoryA/"+subdir+"manifest.json");
filesHolder = manifest.filesToProccess;
tasksHolder = manifest.tasksToRun;
runSequence( tasksHolder , function () {
console.log( " Task ended :" + tasksHolder + " for subdirectory : " + subdir);
});
});
});

Using Gulp to create angular $templateCache per module/directory

So, I'm moving from grunt to gulp (or trying to anyway), and I'm having trouble getting gulp to do what I'm doing in grunt. Specifically the $templateCache stuff.
My angular app is broken up into several components/modules. Each module contains everything it needs to run (controllers, directives, partials, scss, etc.).
Using Grunt, I've been able to boil each module down into 5 files:
module.min.css // all module scss files compiled and concatenated
module.min.js // all module controllers, directives, services, etc. concatenated
module.tpls.min.js // all partials in $templateCache for this module
module.mocks.min.js // all unit test mock objects for this module
module.specs.min.js // all unit test specs for this module
This has worked really well for 2 years now and been a cornerstone of my modular architecture. My only reasons to try out gulp was 1) Curiosity, 2) My grunt file is getting kinda hairy as we add in deployment and environment specific stuff and so far gulp has really slimmed that down.
For the most part, I've figured out how to do all my grunt tasks in gulp, but I'm having trouble figuring out how to generate a template cache file for each module. All the gulp-ng|angular-templates|templatecache plugins take all my partials and create one file. I'd like to take all my files under module/partials/*.html and create a single module.tpls.min.js; and do that for each module.
This was actually a problem with grunt too, but I figured it out with grunt.file.expand().forEach() like this:
grunt.registerTask('prepModules', '...', function(){
// loop through our modules directory and create subtasks
// for each module, modifying tasks that affect modules.
grunt.file.expand("src/js/modules/*").forEach(function (dir) {
// get the module name by looking at the directory we're in
var mName = dir.substr(dir.lastIndexOf('/') + 1);
// add ngtemplate subtasks for each module, turning
// all module partials into $templateCache objects
ngtemplates[mName] = {
module: mName,
src: dir + "/partials/**/*.html",
dest: 'dev/modules/' + mName + '/' + mName + '.tpls.min.js'
};
grunt.config.set('ngtemplates', ngtemplates);
});
});
My current gulp for this same task:
var compileTemplates = gulp.src('./src/js/modules/**/partials/*.html', {base:'.'})
.pipe(ngTemplates())
.pipe(gulp.dest('.'));
I've only really looked at the options, but none of them seemed to do what I wanted. They were all around changing the file name, or the final destination of the file, or a module name, or whatever else; nothing that said anything about doing it for only the directory it happens to be in.
I had thought about using gulp-rename because it worked well for me when doing the CSS compilation:
var compileScss = gulp.src('./src/js/modules/**/scss/*.scss', {base:'.'})
.pipe(sass({includePaths: ['./src/scss']}))
.pipe(rename(function(path){
path.dirname = path.dirname.replace(/scss/,'css');
}))
.pipe(gulp.dest('.'));
However, when I pipe rename() after doing ngTemplates() it only has the path of the final output file (one log entry). When you console.log() path after sass(), it has all the paths of all the files that it found (lots of log entries).
Any ideas? Thanks!
This SO post has the correct answer, but the wasn't coming up in my searches for this specific usage. I was going to vote to close my question, but since someone else might search using my own specific terms (since I did), it seems more appropriate to leave it alone and just redirect to the original question as well as show how I solved my own particular problem.
var fs = require('fs');
var ngTemplates = require('gulp-ng-templates');
var rename = require('gulp-rename');
var modulesDir = './src/js/modules/';
var getModules = function(dir){
return fs.readdirSync(dir)
.filter(function(file){
return fs.statSync(path.join(dir, file)).isDirectory();
});
};
gulp.task('default', function(){
var modules = getModules(modulesDir);
var moduleTasks = modules.map(function(folder){
// get all partials for this module
// parse into $templateCache file
// rename to be /dev/modules/_____/______.tpls.min.js
return gulp.src(modulesDir + folder + '/partials/*.html', {basedir:'.'})
.pipe(ngTemplates({module:folder}))
.pipe(rename(function(path){
path.dirname = './dev/apps/' + folder + '/';
path.basename = folder + '.tpls.min';
}))
.pipe(gulp.dest('.'));
});
});
It's essentially like the tasks per folder recipe but with a change to use gulp-ng-templates. I'll probably be using this same pattern for my SCSS and JS now that I'm more aware of it.
Seems like the gulp equivalent of grunt.file.expand().forEach().
Whenever I deal with scss/sass for gulp tasks, I will only put one scss file as the source parameter. This parameter file is composed of a list of imports. This way you don't need to rely on gulp to concat the scss file contents for you.
//in gulpfile
gulp.src('./src/js/modules/**/scss/main.scss', {base:'.'})
//in main.scss
#import 'a', 'b', 'c';
a, b, and c would represent your other scss files.

Switching Development/Test/Production variables in Javascript

I am trying to search the best approach to manage different values for same variables in Devlopment, Test and Production environment.
For example, I have variable jsonFile which can be:
var jsonFile = http://localhost:63342/json/appsconfig.json
for development env
var jsonFile = http://192.168.35.59/applications/json/appsconfig.json
for test env
var jsonFile = http://example.com/applications/json/appsconfig.json
for production env
I am trying to read a lot about Frontend Development Stack, but I am confused about what tool to use. I will use Google Closure Tools for minification, can it be also useful to switch variable values? Or can it be considered a Grunt task (even if I am not able to understand how to properly configure Grunt tasks...)?
What might be better is to write the JSON into a JS file that is part of your build artifacts. Something like file-creator that can write a file like so (using a simplistic setup that can obviously be made more dynamic).
In the top of your module.exports for grunt tasks, load in the config file into a var like:
var configData = grunt.file.readJSON('../config/appsconfig.json'),
Then write to a new JS file using the grunt file-creator module
"file-creator": {
'dev': {
'build/config.js': function (fs, fd, done) {
fs.writeSync(fd,
'var yourSiteHere = yourSiteHere || {}; yourSiteHere.config = '
+ JSON.stringify(configData) + ";"
);
done();
}
}
}
Then load this JS file into the page (perhaps even minify it using a separate grunt task). You will be then able to refer to the config data like so:
var apiEndPoint = yourSiteHere.config.api.apiEndPoint,
apiKey = yourSiteHere.config.api.apiKey;

rename templates folders with a gruntjs custom init task

I'm trying to create a custom init task for a personal template in Grunt.
This is the js which generate my new project after a grunt init:mytemplate
exports.description = 'Try Grunt';
exports.warnOn = '*';
exports.template = function(grunt, init, done) {
grunt.helper('prompt', {type: 'skin'}, [
grunt.helper('prompt_for', 'name', 'trygrunt'),
grunt.helper('prompt_for', 'title', 'Im Trying GruntJS'),
grunt.helper('prompt_for', 'author_name', 'Myself')
],
function(err, props) {
var files = init.filesToCopy(props);
init.copyAndProcess(files, props);
done();
});
};
Everything works fine: files and folder are correctly generated or renamed from the root folder of the custom template based on rename.json info.
The question is: how can i also dynamically rename folders and not only files?
i.e.
{
"libs/name.js": "libs/{%= name %}.js" //this works fine
"src/name": "src/{%= name %}" //this doesn't work
}
The init.filesToCopy method only looks at renames.json for specific file (not directory) matches when it first builds the files object. Your best bet is to programmatically modify the files object between init.filesToCopy and init.copyAndProcess.
This is possible by modifying the result of the init.filesToCopy object. However you need to modify the key rather than the value of each pair.
For example, I have a folder called lib/ that I wish to copy the contents into app/
var files = init.filesToCopy(props),
libFolder = 'app';
// Repath the files correctly
for (var file in files) {
if (file.indexOf('lib/') > -1) {
var path = files[file],
newFile = file.replace('lib/', libFolder + '/');
files[newFile] = path;
delete files[file];
}
}
init.copyAndProcess(files, props);
It's also worth noting that rename.json works on the lib/ value not the new folder.
One thing that I've done is to use the props.main value to extract the libFolder value (e.g. libFolder = props.main.split('/')[0])
Another way to accomplish this and get around the limitation of not being able to rename folders, is to 1) setup a grunt-contrib-copy task to copy the folders and files and apply whatever names you require to the new folders/files, and then 2) have a grunt-contrib-clean task clean out the old files/folders resulting in the same net effect as renaming the folders.

Categories

Resources