I'm using Browserify to create a bundle which contains an exported function that I want to call within a <script> tag. Everything works fine until I require Bootstrap, at which point the function is no longer accessible and I get the error:
TypeError: mainBundle.greeting is not a function
Here's the code:
JavaScript (main.js):
window.jQuery = require('jquery');
window.$ = global.jQuery;
module.exports = {
greeting
};
function greeting (name) {
return `Hello ${name}!`;
}
HTML
<script src="js/bundle.js"></script>
<script>
// Update greeting
$('#greeting').text(mainBundle.greeting('Foo'));
</script>
Gulpfile:
Taken pretty much from the Gulp Browserify recipe. You can see I've added the standalone option to customOpts to generate a standalone module as well as require to add Bootstrap. The issue occurs when the require line is commented in.
const gulp = require('gulp');
const sourcemaps = require('gulp-sourcemaps');
const concat = require('gulp-concat');
const watchify = require('watchify');
const browserify = require('browserify');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');
const log = require('gulplog');
// add custom browserify options here
const customOpts = {
entries: ['./src/js/main.js'],
// require: ['bootstrap', 'jquery'], // UNCOMMENT CAUSES ISSUE
standalone: 'mainBundle',
debug: true
};
const opts = {...watchify.args, ...customOpts};
const b = watchify(browserify(opts));
console.log('Browserify options: ', opts);
// add transformations here
// i.e. b.transform(coffeeify);
exports.js = bundle; // so you can run `gulp js` to build the file
b.on('update', bundle); // on any dep update, runs the bundler
b.on('log', log.info); // output build logs to terminal
function bundle() {
return b.bundle()
// log errors if they happen
.on('error', log.error.bind(log, 'Browserify Error'))
.pipe(source('bundle.js'))
// optional, remove if you don't need to buffer file contents
.pipe(buffer())
// optional, remove if you dont want sourcemaps
.pipe(sourcemaps.init({loadMaps: true})) // loads map from browserify file
// Add transformation tasks to the pipeline here.
.pipe(sourcemaps.write('./')) // writes .map file
.pipe(gulp.dest('./dist/js'));
}
Hmm, putting the require in main.js resolves the issue:
const bootstrap = require('bootstrap');
window.jQuery = require('jquery');
window.$ = global.jQuery;
module.exports = {
greeting
};
function greeting (name) {
return `Hello ${name}!`;
}
If anyone has a better answer that would allow me to use the Browserify require option, I will happily accept your answer. I would prefer to use the config option to avoid importing things that are not explicitly required in my scripts.
Related
I have been working on modifying this relatively simple gulpfile/project: https://github.com/ispykenny/sass-to-inline-css
The first issue I had was to update to gulp v4, but I've also tried to store variables for my src and destination folders which is a bit easier to control. So now my gulpfile looks like this:
const gulp = require('gulp');
const inlineCss = require('gulp-inline-css');
const sass = require('gulp-sass');
const browserSync = require('browser-sync').create();
const plumber = require('gulp-plumber');
const del = require('del');
const srcFolder = './src'; // TODO tidy this up once working
const buildFolder = srcFolder + '/build/'; // Tidy this up once working
const src = {
scss: 'src/scss/**/*.scss',
templates: 'src/templates/**/*.html'
}
const dest = {
build: 'build/',
css: 'build/css'
};
function processClean() {
return del(`${buildFolder}**`, { force: true });
}
function processSass() {
return gulp
.src(src.scss)
.pipe(plumber())
.pipe(sass())
.pipe(gulp.dest(dest.css))
.pipe(browserSync.stream())
}
function processInline() {
return gulp
.src('./*.html')
.pipe(inlineCss({
removeHtmlSelectors: true
}))
.pipe(gulp.dest('build/'))
}
function processWatch() {
gulp.watch(['./src/scss/**/*.scss'], processSass);
gulp.watch(srcFolder).on('change', browserSync.reload);
gulp.watch(distFolder).on('change', browserSync.reload);
}
const buildStyles = gulp.series(processSass, processInline);
const build = gulp.parallel(processClean, buildStyles);
gulp.task('clean', processClean);
gulp.task('styles', buildStyles);
gulp.task('sass', processSass);
gulp.task('inline', processInline);
gulp.task('build', build);
gulp.task('watch', processWatch);
But I am now wanting to create lots of template files, store them in a subfolder and have gulp spit out each file into the destination folder. if I have index.html, test1.html etc in the root it works fine.
I tried modifying this:
function processInline() { return gulp.src('./*.html')
To this:
function processInline() { return gulp.src(src.templates) // should equate to 'src/templates/**/*html'
Now I'm seeing this error in the console:
ENOENT: no such file or directory, open 'C:\Users\myuser\pathToApp\emailTemplates\src\templates\build\css\style.css'
In the head of index.html in the root is this:
<link rel="stylesheet" href="build/css/style.css">
I actually don't really care about the css file as the final output should be inline (for email templates). But I cannot get my head around why this is happening.
Does gulp create the css file and then read the class names from there? EDIT, Ah I guess it must because it has to convert the sass to readable css first before stripping out the class names and injecting the inline styles.
Years ago I worked with grunt a fair bit, and webpack, but haven't done much with gulp.
I hope it is obvious, but if you need more information just let me know.
When I am trying to save scss files which are imported to main sccs file - every time I need resave main scss file to apply changes. therefore I have decided to install gulp-sass-glob according to this https://www.npmjs.com/package/gulp-sass-glob
but unfortunately it does not work.
Here is my code, please help me how to integrate gulp-sass-glob in my gulp file or what is wrong here. Thank you.
const { src, dest, parallel, series, watch } = require('gulp');
// Load plugins
const sass = require('gulp-sass');
const browsersync = require('browser-sync').create();
const htmlmin = require('gulp-htmlmin');
// Directories
const SRC = './src/';
const DEST = './dist/';
const DEST_CSS = `${DEST}css/`;
const SRC_CSS = `${SRC}scss/*main.scss`;
var gulp = require('gulp');
var sassGlob = require('gulp-sass-glob');
gulp.task('styles', function () {
return gulp
.src(SRC_CSS)
.pipe(sassGlob())
.pipe(sass())
.pipe(gulp.dest(DEST_CSS));
});
// Watch files
function watchFiles() {
watch(`${SRC_CSS}*`, css);
watch(`${SRC}lang`, html);
}
// BrowserSync
function browserSync() {
browsersync.init({
server: {
baseDir: DEST
},
port: PORT
});
}
// Tasks to define the execution of the functions simultaneously or in series
exports.watch = series(
clear,
parallel( css, html, copyStaticHTML, watchFiles, browserSync)
);
exports.default = series(clear, parallel(js, css, html, copyStaticHTML));
I am writing a unit test case for the , question is mentioned in the link How to stub/mock submodules of a require of nodejs using sinon
when I include a require
const index=require('./index.js');
It has a library require inside it
const library= require('./library.js');
the library.js file has a require which reads config.json file(this config file is also required inside above index.js) as below
const readConfig = require('read-config');
const config = readConfig('./config.json');
I have tried many ways as suggested in the above link but I am failing
const stubs = {
'./library': function (response) {
assert.equal(some, null);
return 'Some ' + argument;
},
'../library1.js': {
function(paths, opts){
var config='./config.json'
return config;
}
},
}
const index=proxyquire('./index.js',stubs)
When I run my unit test case I am still getting the below error
throw configNotFound(configPath);
^
ReadConfigError: Config file not found: ./config.json
I would like to know which part of the code I am missing badly that the code throws the error
I am trying to edit the index.js and all the related files where config is read with the below code
var path = require('path');
var pathToJson = path.resolve(__dirname, '../config.json');
// Load config
var config = fs.readFile(pathToJson , 'utf8', function (err, data) {
if (err) throw err;
config = JSON.parse(data);
});
Here challenge is that I cannot change the node code
You problem is likely to be path resolution. If ./config.json is relative to where you are running Node from (process.cwd()), then it'll work. If it's relative to your library module, then you can do something like:
// Works for JS and JSON
const configPath = require.resolve('./config.json');
// Works in general
const configPath = require('path').join(__dirname, 'config.json');
// Then
const readConfig = require('read-config');
const config = readConfig(configPath);
It's difficult to say if this is the case without knowing more about your project layout and how you're starting your app.
With the Browserify API and Gulp, I have this:
var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var dependencies = [
'lodash',
'./test.js',
];
gulp.task('lib', function() {
return browserify()
.require(dependencies)
.bundle()
.pipe(source('lib.js'))
.pipe(gulp.dest('./'));
});
gulp.task('app', function() {
return browserify('./app.js')
.external(dependencies)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest('./'));
});
And in app.js I have this:
var _ = require('lodash');
var test = require('./test.js');
The Lodash line works fine, but the ./test.js does not work. I get the error Error: Cannot find module '/test.js'.
How do I get this to work?
For some reason, the key differs between bundle.js and lib.js. In lib.js, the key for test.js is the full path (/Users/gary/Projects/browserify-test/test.js) whereas in bundle.js it's looking for a module with the key ./test.js. If I manually change the latter to be the same as the former, then it works.
I'm guessing that ultimately, Browserify doesn't support require on local files that are excluded from the same bundle.
browserify needs an absolute path to retrieve the file and it leaves that as the bundle key. The way to fix it is to use the expose option...
In your build..
var dependencies = [
'lodash',
{file: './test.js', expose: 'test'},
];
and in app.js...
var _ = require('lodash');
var test = require('test');
I’d like to make npm module which returns stream and then pipe it to gulp.dest in some other app.
Example:
// some-module.js
module.exports = function() {
return require('fs').createReadStream('someFile.txt');
}
// gulpfile.js
gulp.task('default', function() {
var myModule = require('./some-module');
myModule().pipe(gulp.dest('./'));
});
Unfortunately for this code I got:
path.js:313
throw new TypeError('Arguments to path.resolve must be strings');
^
TypeError: Arguments to path.resolve must be strings
It works in this way
// gulpfile.js
gulp.task('default', function() {
var myModule = require('./some-module');
var fs = require('fs');
myModule().pipe(fs.createWriteStream('someOtherFile.txt');
});
You can use vinyl-source-stream to convert your stream into a gulp-compatible stream.
Get it:
npm install vinyl-source-stream --save-dev
Usage:
// gulpfile.js
var source = require('vinyl-source-stream');
gulp.task('default', function() {
var myModule = require('./some-module');
myModule()
.pipe(source('someOtherFile.txt'))
.pipe(gulp.dest('./'));
});
The parameter to source() will be the filename used by gulp.dest().