I have 2 separate script files for 2 different html pages. like this
-/src
-/pages
-main.html
-info.html
-/js
-main.js
-info.js
I need gulp to generate 2 separate JS files from /src folder to /public folder.
Here's my script task:
function scripts() {
return src('./src/js/main.js')
.pipe(
includeFiles({
includePaths: './src/components/**/',
})
)
.pipe(dest('./public/js/'))
.pipe(browserSync.stream())
}
I realize it could be done through a cycle. Just can't figure out how exactly. I tried this , but didn't work
let scripts = ['./src/js/index.js','./src/js/info.js']
function handleScripts(){
scripts.forEach( link => {
return src(link)
.pipe(
includeFiles({
includePaths: './src/components/**/',
})
)
.pipe(dest('./public/js/'))
.pipe(browserSync.stream())
})
}
Related
I have the following gulp task for my js files:
gulp.task("js", () => {
return gulp
.src([
src_js_folder + "*.js",
src_js_folder + "**/*.js" // Include partial js files, to trigger the build when there is a change in them
], { since: gulp.lastRun("js"), read: false }) // no need of reading file because browserify does.
.pipe(dependents())
.pipe(filter(['**'].concat( // filter partial js files (inside subdirectories)
readdirSync(src_js_folder, { withFileTypes: true }) // list all js files inside subdirectories
.filter(dirent => dirent.isDirectory())
.map(dirent => `!${src_js_folder.substring(2) + dirent.name}/**/*.js`)
)))
.pipe(plumber({errorHandler: reportError}))
.pipe(tap(function (file) {
logger.info('bundling ' + file.path);
// replace file contents with browserify's bundle stream
file.contents = browserify(file.path, {debug: true})
.bundle();
}))
.pipe(buffer()) // transform streaming contents into buffer contents (because gulp-sourcemaps does not support streaming contents)
.pipe(beautify.js({ indent_size: 2 }))
.pipe(gulp.dest(dist_folder + "js"))
.pipe(browserSync.stream());
});
And this watcher for browserSync:
gulp.watch([src_js_folder + '**/*.js'], gulp.series("dev")).on("change", browserSync.reload);
So what I did in my task is I included the partial js files in the src as well, and then filter them to not build them.
The problem I'm having is that when I update a parent js file that includes these partials gulp is rebuilding them, but when I change something in the partials, gulp doesn't build the parent js files that include these partials.
for example if I change the following file: src_js_folder + 'somefile.js', gulp successfully rebuild the file:
[16:27:34] Starting 'js'...
[16:27:34] bundling ...\www-src\assets\scripts\global.V3-1.js
[Browsersync] 1 file changed (global.V3-1.js)
[16:27:34] Finished 'js' after 597 ms
But when I change something in the partial js file, for example: src_js_folder + '/subdir/_somePartialFile.js', gulp does nothing:
[16:29:21] Starting 'js'...
[16:29:21] Finished 'js' after 10 ms
The logic I followed in my task is the same as my sass task:
gulp.task("sass", () => {
return (
gulp.src([
src_sass_folder + "*.scss",
src_sass_folder + "**/*.scss"
], {
since: gulp.lastRun("sass"),
})
.pipe(dependents())
.pipe(filter(['**'].concat( // filter partial SASS files (inside subdirectories) this is used to not build the partial SASS files
readdirSync(src_sass_folder, { withFileTypes: true }) // selector for all partial SASS files
.filter(dirent => dirent.isDirectory())
.map(dirent => `!${src_sass_folder.substring(2) + dirent.name}/**/*.scss`)
)))
.pipe(debug({title: "sass-debug:", showCount: false}))
.pipe(sourcemaps.init())
.pipe(plumber({errorHandler: reportError}))
.pipe(sass({ fiber: Fiber })) // call asynchronous importers from the synchronous code path (for using Dart Sass)
.pipe(autoprefixer())
.pipe(minifyCss({debug: true}, (details) => {
console.log(`Original size: ${details.stats.originalSize}, Minified size: ${details.stats.minifiedSize}, Efficiency: ${details.stats.efficiency}`);
}))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(dist_folder + "Content"), {overwrite: true})
.pipe(browserSync.stream({match: '**/*.css'}))
);
});
gulp.watch([src_sass_folder + '**/*.scss'], gulp.series("sass"));
This is successfully working when I change something in the partial sass files, because when a partial sass file changes, gulp only builds the sass files that include them.
How can I make my js task work properly?
Edit:
My parent js files are looking like this:
bundle = require('./subdir/_partial1.js');
bundle = require('./subdir/_partial2.js');
bundle = require('./subdir/_partial3.js');
I was able to use gulp-dependents for setting up JS(ES6) incremental build.
For that I had to write the regex for extracting the file paths from the import statements and fortunately I found a GitHub Gist which had the required regex. Here is the gulp-dependents config for parsing JS import statements:
const jsDependentsConfig = {
".js":{
postfixes: ['.js'],
parserSteps: [
/import(?:["'\s]*(?:[\w*${}\n\r\t, ]+)from\s*)?["'\s]*(.*[#\w_-]+)["'\s].*;?$/gm,
function(path){
// Remove file extension, if any
path = path.replace(/\.js$/,'');
// Local packages
paths = [`${path}/index.js`,`${path}.js`];
return paths;
},
]
},
};
Once this was implemented, using gulp-dependents was fairly straightforward.
Final code:
const { src, dest, lastRun } = require('gulp');
const dependents = require('gulp-dependents');
const filter = require('gulp-filter');
const jsDependentsConfig = {
".js":{
postfixes: ['.js'],
parserSteps: [
/import(?:["'\s]*(?:[\w*${}\n\r\t, ]+)from\s*)?["'\s]*(.*[#\w_-]+)["'\s].*;?$/gm,
function(path){
// Remove file extension, if any
path = path.replace(/\.js$/,'');
// Local packages
paths = [`${path}/index.js`,`${path}.js`];
return paths;
},
]
},
};
function scripts(){
// Ref: https://stackoverflow.com/a/35413106
const filterPartials = filter([
`**/src/js/**/!(_)*.js`, // select all js files
`!**/src/js/**/_*/`, // exclude all folder starting with _
`!**/src/js/**/_*/**/*` //exclude files/subfolders in folders starting with '_'
]);
return src('src/js/**/*.js',{ since: lastRun(scripts) })
.pipe(gulpIf(!Config.production,
dependents(jsDependentsConfig)
))
.pipe(filterPartials)
// other pipes
.pipe(dest('assets/js'))
;
}
Is dependents gulp-dependents?
By default, gulp-dependents do not support .js files.
When 'partial sass file' is changed, gulp-dependents add 'parent sass file' by dependencyMap cached before. Then filter remove the 'partial sass file'. The 'parent sass file' is passed to gulp-sass.
When 'partial js file' is changed, gulp-dependents do not add any file. Then filter remove the 'partial js file'. No file last.
Cache dependencies by browserify pipeline.
function DependentsJS () {
const fileDepMap = new Map()
return {
browserify (filePath, opts) {
for (let deps of fileDepMap) {
deps[1].delete(filePath)
}
const b = browserify(filePath, opts)
b.pipeline.on('file', function (file) {
if (!fileDepMap.has(file)) {
fileDepMap.set(file, new Set())
}
fileDepMap.get(file).add(filePath)
})
return b
},
plugin: () => through.obj(function (file, encoding, callback) {
this.push(file)
if (fileDepMap.has(file.path)) {
fileDepMap.get(file.path).forEach(pFile => {
this.push({
cwd: file.cwd,
path: pFile
})
});
}
callback();
}, function (callback) {
callback()
})
}
}
USE:
const dependentsJS = DependentsJS()
gulp.task("js", () => {
return gulp
.src([
src_js_folder + "*.js",
src_js_folder + "**/*.js"
], { since: gulp.lastRun("js"), read: false })
// .pipe(dependents())
.pipe(dependentsJS.plugin()) // <<< USE `dependentsJS.plugin()`
.pipe(filter(['**'].concat(
readdirSync(src_js_folder, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => `!${src_js_folder.substring(2) + dirent.name}/**/*.js`)
)))
.pipe(plumber({errorHandler: reportError}))
.pipe(tap(function (file) {
logger.info('bundling ' + file.path);
// file.contents = browserify(file.path, {debug: true})
file.contents = dependentsJS.browserify(file.path, {debug: true}) // <<< USE `dependentsJS.browserify`
.bundle();
}))
.pipe(buffer())
.pipe(beautify.js({ indent_size: 2 }))
.pipe(gulp.dest(dist_folder + "js"))
.pipe(browserSync.stream());
});
I know that this can be a very stupid question, but I can't find matches with other posts on stackoverflow...
So: Can I modify a file of an external module , just save the file and do something that my app can listen?
At the moment, i'm trying ti change some scss style at the ng2-datepicker module (inside node_modules folder), but if I save and the launch ng serve, changes will not affect my project.
I know it's a simple problem, but i don't know the background architecture of an Angular2 project.
Thanks in advance.
(ps I've seen that i can fork the git and then do something like npm install.
Very interesting, but i also want to know how to have the same result in local)
If you are using gulp file you can tell the changed lib file path to copy to build folder check gulp.task('copy-libs') in code below git repo for angular2-tour-of-heroes using gulp
const gulp = require('gulp');
const del = require('del');
const typescript = require('gulp-typescript');
const tscConfig = require('./tsconfig.json');
const sourcemaps = require('gulp-sourcemaps');
const tslint = require('gulp-tslint');
const browserSync = require('browser-sync');
const reload = browserSync.reload;
const tsconfig = require('tsconfig-glob');
// clean the contents of the distribution directory
gulp.task('clean', function () {
return del('dist/**/*');
});
// copy static assets - i.e. non TypeScript compiled source
gulp.task('copy:assets', ['clean'], function() {
return gulp.src(['app/**/*', 'index.html', 'styles.css', '!app/**/*.ts'], { base : './' })
.pipe(gulp.dest('dist'))
});
// copy dependencies
gulp.task('copy:libs', ['clean'], function() {
return gulp.src([
'node_modules/angular2/bundles/angular2-polyfills.js',
'node_modules/systemjs/dist/system.src.js',
'node_modules/rxjs/bundles/Rx.js',
'node_modules/angular2/bundles/angular2.dev.js',
'node_modules/angular2/bundles/router.dev.js',
'node_modules/node-uuid/uuid.js',
'node_modules/immutable/dist/immutable.js'
'yourpath/changedFileName.js'
])
.pipe(gulp.dest('dist/lib'))
});
// linting
gulp.task('tslint', function() {
return gulp.src('app/**/*.ts')
.pipe(tslint())
.pipe(tslint.report('verbose'));
});
// TypeScript compile
gulp.task('compile', ['clean'], function () {
return gulp
.src(tscConfig.files)
.pipe(sourcemaps.init())
.pipe(typescript(tscConfig.compilerOptions))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('dist/app'));
});
// update the tsconfig files based on the glob pattern
gulp.task('tsconfig-glob', function () {
return tsconfig({
configPath: '.',
indent: 2
});
});
// Run browsersync for development
gulp.task('serve', ['build'], function() {
browserSync({
server: {
baseDir: 'dist'
}
});
gulp.watch(['app/**/*', 'index.html', 'styles.css'], ['buildAndReload']);
});
gulp.task('build', ['tslint', 'compile', 'copy:libs', 'copy:assets']);
gulp.task('buildAndReload', ['build'], reload);
gulp.task('default', ['build']);
I wonder if there is an easy way to detect if two tasks write to the same file.
In this example there is a /js directory alongside a /ts directory. The /ts will get transpiled to the same directory as the /js. There shouldn't be any collisions. The ask is that, if there are collisions, the ts will win; but, I would like to warn that there is a collision.
gulp.task('js', function() {
return es.concat(
gulp.src(config.src.path('js', '**', '*.js'))
.pipe(gulp.dest(config.build.path(app, 'js')))
//, ....
);
});
gulp.task('ts', ['js'], function() {
var tsResult = gulp.src(config.src.path('ts', '**', '*.ts'))
.pipe(ts({
declaration: true,
noExternalResolve: true
}));
return es.concat([
tsResult.dts.pipe(gulp.dest(
config.build.path(app, 'definitions'))),
tsResult.js.pipe(gulp.dest(
config.build.path(app, 'js'))) // <--- same dest as js task
]);
})
Can I detect that the ts task is overwriting a file that the js task just put in place?
Just an idea. You can pass a callback to gulp.dest like this:
gulp.src('lib/*.js')
.pipe(uglify())
.pipe(gulp.src('styles/*.css'))
.pipe(gulp.dest(function(file) {
if (fs.existsSync('something here')) { // it's a deprecated call, use a newer one
console.warn("File exists", file);
}
// I don't know, you can do something cool here
return 'build/whatever';
}));
The feature is available since Gulp 3.8: https://github.com/gulpjs/gulp/blob/master/CHANGELOG.md#380
Other resources:
https://stackoverflow.com/a/29437418/99256
https://stackoverflow.com/a/29817916/99256
I'm using two separate gulp tasks to minify templates into js file (1) and concat all js file of the project to the only minified (2).
gulp.task('templates', function() { // RESULT of this task
return gulp.src('templates/**/*.html')
.pipe(dotify({
root : 'templates'
}))
.pipe(concat('templates.js'))
.pipe(gulp.dest('js'));
});
gulp.task('minifyJs', ['templates'], function() {
return gulp.src([
'js/templates.js',
'js/plugins/*.js',
'js/*.js'
])
.pipe(concat('scripts-all.js'))
});
The question is: am I able to avoid creating the templates.js file by processing the result from first task to the second one to concat it with the rest of js's?
Solution: addSrc should be used
return gulp.src('templates/**/*.html')
.pipe(dotify({
root : 'templates'
}))
.pipe(addSrc([
'js/plugins/*.js',
'js/common/*.js',
'js/ui/*.js',
'js/pages/*.js',
'js/*.js'
]))
.pipe(concat('scripts-all.js'))
.pipe(gulp.dest('js/'));
I'd like to use my NodeJS module in the browser - so I'm using browserify to process it.
Now, how can I stop browserify from including the module's dependencies in the bundle file? In this case the dependency is lodash and I'll be loading it separately in the index.html.
Here's what I've got so far:
index.html
<script src="lodash.js"></script>
<script src="my-module.js"></script>
index.js
var _ = require('lodash');
_.each([0, 1, 2], function(item) {
console.log(item);
});
gulp.js
var browserify = require('browserify'),
source = require('vinyl-source-stream');
gulp.task('browserify', function() {
return browserify()
.require('./index.js', {
expose: 'my-module'
})
.bundle()
.pipe(source('my-module.js'))
.pipe(gulp.dest('./'));
});
browserify-shim offers the option of setting up globals.
Here are the changes I've made to my code.
package.json
{
"browserify-shim": {
"lodash": "global:_"
},
"browserify": {
"transform": ["browserify-shim"]
}
}
gulp.js
gulp.task('browserify', function() {
return browserify('./index.js')
.require('./index.js', {
expose: 'my-module'
})
.transform('browserify-shim', {
global: true
})
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest('./'));
});
There's an option to exclude files:
Usage: browserify [entry files] {OPTIONS}
[...]
--ignore, -i Replace a file with an empty stub. Files can be globs.
--exclude, -u Omit a file from the output bundle. Files can be globs.
https://github.com/substack/node-browserify#usage
And the corresponding exclude function:
b.exclude(file)
Prevent the module name or file at file from showing up in the output bundle.
If your code tries to require() that file it will throw unless you've provided another mechanism for loading it.
So you should try this:
return browserify()
.require('./index.js', {
expose: 'my-module'
})
.exclude('lodash.js')
.bundle();
I figured this out.
const nodeOnlyModule = eval('require')('module-name');
This way you can trick browserify.