gulp : build several dist for website, each with own custom js - gulp

I'm currently developing a small website, used a bootstrap template that includes gulp which I am fairly new to.
The gulpfile already has a build function to build a dist directory for the final website.
The trick is that I want to build several websites, that will vary by the contents of a javascript file I want to load on some pages, I consequently have 6 of these javascript files ready.
I figured out the gulp part on the html files that works ok :
##if (context.test == 1) {
##include("partials/scripts_shop_1.html")
}
##if (context.test == 2) {
##include("partials/scripts_shop_2.html")
}
and so on...
My gulp file looks as such
gulp.task('copy:all', function() {
return gulp
.src([
paths.src.base.files,
'!' + paths.src.partials.dir,
'!' + paths.src.partials.files,
'!' + paths.src.scss.dir,
'!' + paths.src.scss.files,
'!' + paths.src.tmp.dir,
'!' + paths.src.tmp.files,
'!' + paths.src.js.dir,
'!' + paths.src.js.files,
'!' + paths.src.css.dir,
'!' + paths.src.css.files,
'!' + paths.src.html.files
])
.pipe(gulp.dest(paths.dist.base.dir));
});
gulp.task('copy:libs', function() {
return gulp.src(npmdist(), {
base: paths.base.node.dir
}).pipe(gulp.dest(paths.dist.libs.dir));
});
gulp.task('html', function() {
return gulp
.src([paths.src.html.files, '!' + paths.src.tmp.files, '!' + paths.src.partials.files])
.pipe(
fileinclude({
prefix: '##',
basepath: '#file',
indent: true,
context: {'test': 1}
})
)
.pipe(replace(/href="(.{0,10})node_modules/g, 'href="$1assets/libs'))
.pipe(replace(/src="(.{0,10})node_modules/g, 'src="$1assets/libs'))
.pipe(useref())
.pipe(cached())
.pipe(gulpif('*.js', uglify()))
.pipe(gulpif('*.css', cleancss()))
.pipe(gulp.dest(paths.dist.base.dir));
});
gulp.task(
'build',
gulp.series(
gulp.parallel('clean:tmp', 'clean:dist', 'copy:all', 'copy:libs'),
'scss',
'html'
)
);
You can see the test parameter that allows me to tell which version of the script I want to load in the html file.
What I would like to do is to be able to have a gulp task that builds all 6 websites as once, and so to be able to pass a parameter in the html function and run it in a loop. I have the same thing to do with the copy function to chose different directories but I assume it will be the same process to follow.
Any help would be appreciated :)
Edward

In the end, I ran into problems regarding gulp caching some assets from first website that had to change on others. Using gulp options to disable caching led to other issues.
The solution I found was not to generate all sites within the same gulp file but use parameters as explained in this article. I understand this is not recommended but it works for me here.

Related

browsersync reload when a nunjucks partial file is modified

I have a gulp task as following:
gulp.task("nunjucks", () => {
return gulp
.src([src_folder + "pages/**/*.njk"])
.pipe(plumber())
.pipe(
data(() =>
JSON.parse(fs.readFileSync(src_folder + "datas/dist/data.json"))
)
)
.pipe(nunjucks())
.pipe(beautify.html({ indent_size: 2 }))
.pipe(gulp.dest(dist_folder))
.pipe(browserSync.stream({match: '**/*.html'}));
});
gulp.watch([src_folder + '**/*.njk'], gulp.series("nunjucks")).on("change", browserSync.reload);
and my project structures look like this:
atoms, molecules and organisms contains nunjucks partials.
The problem I have is that whenever I update a partial file (ex: organisms/partial1.njk), my task detects changes on all the files inside pages (the path I provided for the task src), as you can see here :
I only want to reload the files that includes this partial and not all the files.
How can I solve this?
Its not up to your gulp task to know which one of your Nunjuck pages contain partials. Perhaps if you re-group your .njk files within your Pages folder, you could then better manage what gets reloaded. The following is untested, but hopefully conveys the idea...
pages/
- init/
- other-stuff/
You could then update the src from your gulp task to something like so...
gulp.src([
'!pages/other-stuff/**/*',
'pages/init/**/*.njk'
])

Change dest folder for gulp

I'm using the plugin gulp-nunjucks-render with gulp as following:
gulp.task("nunjucks", () => {
return gulp
.src(src_folder + "pages/**/*.njk", {
base: src_folder,
since: gulp.lastRun("nunjucks"),
})
.pipe(plumber())
.pipe(
data(() =>
JSON.parse(fs.readFileSync(src_folder + "datas/dist/data.json"))
)
)
.pipe(nunjucks())
.pipe(beautify.html({ indent_size: 2 }))
.pipe(gulp.dest(dist_folder))
.pipe(browserSync.stream());
});
I want the generated html files to be inside the dist_folder and not inside dist_folder + "pages".
How can I achieve that?
You probably just need .pipe(dest('dist_folder')) appending as per these docs: https://gulpjs.com/docs/en/api/dest/
gulp.task("nunjucks", () => {
return gulp
.src(src_folder + "pages/**/*.njk", {
base: src_folder,
since: gulp.lastRun("nunjucks"),
})
.pipe(plumber())
.pipe(
data(() =>
JSON.parse(fs.readFileSync(src_folder + "datas/dist/data.json"))
)
)
.pipe(nunjucks())
.pipe(beautify.html({ indent_size: 2 }))
.pipe(gulp.dest(dist_folder))
.pipe(browserSync.stream())
.pipe(dest('dist_folder'));
});
You want to remove the pages directory so as mentioned here glob-base, pages needs to be part of your base:
A glob base - sometimes called glob parent - is the path segment
before any special characters in a glob string. As such, the glob base
of /src/js/**.js is /src/js/.
Vinyl instances generated by src() are constructed with the glob base
set as their base property. When written to the file system with
dest(), the base will be removed from the output path to preserve
directory structures.
It is naturally part of your base (it is before the globstar ** in your src) so if you remove the base property that you added you will get the behaviour you wanted since
"When written to the file system with
dest(), the base will be removed from the output path".
Gulp will automatically set the base to src_folder + "pages" if you remove the base option that you set.
Alternatively, if you do want to specifically set the base property you could use this:
return gulp
.src(src_folder + "pages/**/*.njk", {
base: src_folder + "pages",
since: gulp.lastRun("nunjucks"),
})
...
which in your specific case does exactly the same thing as not setting the base property at all!

How to run gulp tasks with different parameters depending on the argument on terminal

I have a shared SCSS source files which must be compiled and copied into different project folders.
I have a build task which calls 2 tasks, clean and styles(to compile/minify and copy to build folder).
My source SCSS files are shared between all websites however the destination folders are different.
I would like to be able to run: build websiteA and then clean build folder inside websiteA and compile files from a shared folder and copied to build folder inside Website A.
var assetsDir = '_Assets';
var buildStyleWebsiteA = 'WebsiteA/Assets/build';
var buildStyleWebsiteB = 'WebsiteB/Assets/build';
gulp.task('clean-websiteA', function (cb) {
return del([buildStyleWebsiteA ], cb);
});
gulp.task('styles-websiteA', ['clean-websiteA'], function () {
return gulp.src(assetsDir + '/**/*.scss')
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(autoprefixer())
.pipe(gulp.dest(buildStyleWebsiteA + '/css'))
.pipe(concat('styles.css'))
.pipe(cleanCss())
.pipe(sourcemaps.write())
.pipe(rename({ suffix: '.min' }))
.pipe(gulp.dest(buildStyleWebsiteA + '/min/'))
.pipe(liveReload());
});
gulp.task('build-websiteA', ['styles']);
PS: I also have same tasks for websiteB (build-websiteB, clean-websiteB, and style-websiteB).
So I ended up with repetitive code and I know there must be a better way.
What I would like to have is provide website name as a parameter for gulp command and then it runs clean and style using correct folder related to that website.
How can I refactor my code to achieve that?
Thanks
I would use environment variables to accomplish this rather than arguments.
var buildDir = process.env.BUILD_DIR + '/Assets/build';
Then you would call it as:
BUILD_DIR=websiteA gulp build

browser-sync css injection not working for cache-busted css files

I am using gulp-rev to cache-bust my compiled scss files. This means the css injections works only when I don't change anything in my css file. If I change anything, gulp-rev will give the file a different name and browserSync won't know to inject it. Here is the scss task in my gulpfile:
Object.keys(styles).forEach(function(key){
gulp.task('css-' + key, function(){
del.sync([
'./public/' + styles[key].dir + manifest[key + '.css'],
'./public/' + styles[key].dir + '/maps/' + manifest[key + '.css'] + '.map'
]);
return gulp.src('./source/' + styles[key].dir + key + '.scss')
.pipe(plumber())
.pipe(sourcemaps.init())
.pipe(sass())
.pipe(minifycss())
.pipe(autoprefixer())
.pipe(rev())
.pipe(sourcemaps.write('maps/'))
.pipe(tap(updateManifest))
.pipe(gulp.dest('public/' + styles[key].dir))
.pipe(gulpif(
function(file){return path.extname(file.path) === '.css'},
browsersync.stream()
));
});
});
I believe in general you shouldn't be doing revisions during the development process. If you're worried about cache busting usually it shouldn't be a problem and you can always hard reload. However, you can also configure your local dev server to set the max-age to 0 or set the header Cache-Control: no-cache.
You should have a separate gulp task for your distribution (or apply rev only when building a dist version).

How should I create a complete build with Gulp?

Just learning Gulp. Looks great, but I can't find any information on how to make a complete distribution with it.
Let's say I want to use Gulp to concatenate and minify my CSS and JS, and optimise my images.
In doing so I change the location of JS scripts in my build directory (eg. from bower_components/jquery/dist/jquery.js to js/jquery.js).
How do I automatically update my build HTML/PHP documents to reference the correct files? What is the standard way of doing this?
How do I copy over the rest of my project files?. These are files that need to be included as part of the distribution, such as HTML, PHP, various txt, JSON and all sorts of other files. Surely I don't have to copy and paste those from my development directory each time I do a clean build with Gulp?
Sorry for asking what are probably very n00bish questions. It's possible I should be using something else other than Gulp to manage these, but I'm not sure where to start.
Many thanks in advance.
Point #1
The way i used to achieve this:
var scripts = [];
function getScriptStream(dir) { // Find it as a gulp module or create it
var devT = new Stream.Transform({objectMode: true});
devT._transform = function(file, unused, done) {
scripts.push(path.relative(dir, file.path));
this.push(file);
done();
};
return devT;
}
// Bower
gulp.task('build_bower', function() {
var jsFilter = g.filter('**/*.js');
var ngFilter = g.filter(['!**/angular.js', '!**/angular-mocks.js']);
return g.bowerFiles({
paths: {
bowerDirectory: src.vendors
},
includeDev: !prod
})
.pipe(ngFilter)
.pipe(jsFilter)
.pipe(g.cond(prod, g.streamify(g.concat.bind(null, 'libs.js'))))
.pipe(getScriptStream(src.html))
.pipe(jsFilter.restore())
.pipe(ngFilter.restore())
.pipe(gulp.dest(build.vendors));
});
// JavaScript
gulp.task('build_js', function() {
return gulp.src(src.js + '/**/*.js', {buffer: buffer})
.pipe(g.streamify(g.jshint))
.pipe(g.streamify(g.jshint.reporter.bind(null, 'default')))
.pipe(g.cond(prod, g.streamify(g.concat.bind(null,'app.js'))))
.pipe(g.cond(
prod,
g.streamify.bind(null, g.uglify),
g.livereload.bind(null, server)
))
.pipe(gulp.dest(build.js))
.pipe(getScriptStream(build.html));
});
// HTML
gulp.task('build_html', ['build_bower', 'build_js', 'build_views',
'build_templates'], function() {
fs.writeFile('scripts.json', JSON.stringify(scripts));
return gulp.src(src.html + '/index.html' , {buffer: true})
.pipe(g.replace(/(^\s+)<!-- SCRIPTS -->\r?\n/m, function($, $1) {
return $ + scripts.map(function(script) {
return $1 + '<script type="text/javascript" src="'+script+'"></script>';
}).join('\n') + '\n';
}))
.pipe(gulp.dest(build.html));
});
It has the advantages of concatenating and minifying everything for production while include every files for testing purpose keeping error line numbers coherent.
Point 2
Copying files with gulp is just as simple as doing this:
gulp.src(path).pipe(gulp.dest(buildPath));
Bonus
I generally proceed to deployment by creating a "build" branch and just cloning her in the production server. I created buildbranch for that matter:
// Publish task
gulp.task('publish', function(cb) {
buildBranch({
branch: 'build',
ignore: ['.git', '.token', 'www', 'node_modules']
}, function(err) {
if(err) {
throw err;
}
cb();
});
});
To loosely answer my own question, several years later:
How do I automatically update my build HTML/PHP documents to reference the correct files? What is the standard way of doing this?
Always link to dist version, but ensure sourcemaps are created, so the source is easy to debug. Of course, the watch task is a must.
How do I copy over the rest of my project files?. These are files that need to be included as part of the distribution, such as HTML, PHP, various txt, JSON and all sorts of other files. Surely I don't have to copy and paste those from my development directory each time I do a clean build with Gulp?
This usually isn't a problem as there aren't offer too many files. Large files and configuration are often kept out if the repo, besides.