require not defined with gulp-browserify - javascript

I'm trying to load modules in browser but I'm getting this error:
Uncaught ReferenceError: require is not defined
What I'm doing is creating the js in main.js and sending it over into the build as app.js
Here's my gulpfile.js
var browserify = require('gulp-browserify');
...
gulp.task('scripts', function() {
gulp.src('src/scripts/main.js')
.pipe(browserify({
insertGlobals : true,
debug : !gulp.env.production
}))
.pipe(gulp.dest('build/js'))
});
...
gulp.task('default', ['clean', 'concat', 'uglify', 'scripts']);
And my main.js
var fs = require('fs');
function getIt() {
var items = fs.readFileSync("../../data/data.json");
var jsonItems = JSON.parse(items);
console.log(jsonItems);
}
getIt();
How can I make this work in my template?

If you need external requires, you'll have to set the require property with the name of the file on the options object you pass to browserify. This will make browserify create the require function for you, so you can use later on use it outside the produced script.
...
.pipe(browserify({
insertGlobals : true,
require : ['src/scripts/main.js'],
debug : !gulp.env.production
}))
...

Related

Fetch requirejs.config from Gruntfile

Is there any way to import a requirejs config in to my grunt config file? Right now I have to keep two identical versions, one in app/main.js and one in my Gruntfile.js:
module.exports = function(grunt) {
// can I import app/main.js requireConfig here?
var requireConfig = {
paths: {
jquery: 'lib/jquery'
// etc...
}
};
});
My main.js looks something like this:
requirejs.config({
paths: {
jquery: 'lib/jquery'
// etc...
}
});
define(['app'], function(app){
app.start();
});
You can use standard module pattern which supports different type of module system like following.
Your requirejs config file like this
amd-config.js
(function(factory) {
if (typeof define === 'function' && define.amd) {
// Register as an AMD module if available...
define('amd-config', [], factory());
} else if (typeof exports === 'object') {
// Next for Node.js, CommonJS, browserify...
module.exports = factory();
} else {
// setting browser global when none of the above are available
window.amdConfig = factory();
}
}
(function() {
var amdConfig = {
baseUrl: 'scripts',
paths: {
//Paths here
}
};
return amdConfig;
}));
In gruntfile you can just require like any other module.
var requireConfig = require('amd-config');
Include it normally like you do in index.html with script tag before app.js
and then in app.js use it like following.
requirejs.config(window.amdConfig);
define(['app'], function(app){
app.start();
});
PS: There are cleaner way of including it in app.js.
More cleaner than second, create global variable require and include the script before requirejs script. requirejs checks if there is global variable with name require containing object. If its there, it is used as a config object. So you dont have to call requirejs.config yourself.
You can require the file like you require other files. In that case it will be treated as a require module and you will receive the object in require callback. call your requirejs.config like following.
```
require(['amd-config'], function(amdConfig){
requirejs.config(amdConfig);
require(['app'], function(app){
app.start();
});
});
```
A simpler approach you could use, if you are using grunt to build the project. You can simply use:
options:{
mainConfigFile: "path/to/Config.js"
}
granted you need to use:
https://github.com/gruntjs/grunt-contrib-requirejs
You can try something like this:
function getRequireConfig(requireFilePath) {
var config;
var configFileContent,
_require;
_require = require;
require = {
data: {},
config : function (configParam) {
this.data = configParam;
},
get : function () {
return this.data;
}
};
configFileContent = readFileSync(requireFilePath);
eval(configFileContent);
config = require.get();
require = _require;
return config;
}
What it is doing is:
Override require definition to a custom implementation
Load require config file
Eval it so that the config function of custom implementation will be
called Get the config object from data

How to process *.js and *.min.js bower files in gulp

In my gulp file to inject bower components I have this bad style code duplication. But I do not have any ideas how to get rid of it.
Generally speaking we cannot say just bower_components/**/*.js because we don't want to import all files, plus for production we want to import just .min files. Again. I cannot guaranty that every package I use have .js and .min.js files. So just *.js and *.min.js may not work.
gulp.task('inject', () => {
let sources = gulp.src([
// jquery
'public/bower_components/jquery/dist/jquery.js',
// bootstrap
'public/bower_components/bootstrap/dist/js/bootstrap.js',
'public/bower_components/bootstrap/dist/css/bootstrap.css',
// angular
'public/bower_components/angular/angular.js',
'public/bower_components/angular/angular-csp.css',
// angular route
'public/bower_components/angular-route/angular-route.js',
],{read: false});
let min_sources = gulp.src([
// jquery
'public/bower_components/jquery/dist/jquery.min.js',
// bootstrap
'public/bower_components/bootstrap/dist/js/bootstrap.min.js',
'public/bower_components/bootstrap/dist/css/bootstrap.min.css',
// angular
'public/bower_components/angular/angular.min.js',
'public/bower_components/angular/angular-csp.css',
// angular route
'public/bower_components/angular-route/angular-route.min.js',
],{read: false});
return gulp.src('public/build/index.html')
.pipe(gulpif(!argv.production, inject(sources, {relative: true})))
.pipe(gulpif(argv.production, inject(min_sources, {relative: true})))
.pipe(gulp.dest('public/build/'));
});
But this code duplication isn't solution. I think. How can I improve this part, besides to move this two array in bower.js file ?
Maybe you can use config.js. Use var config = require('../config'); to read the variables in config.js so you can separate file paths and task.
If you want to separate .js and .min.js , you can use
'src' : [
'src/**/*.js',
'!src/**/*.min.js',
]
For example below I concat .min.js / .js files and uglify it, and also concate .css files and use cssnano() to compress it. In the end vendor task will output vendor.bundle.js and vendor.bundle.css
config.js:
'use strict';
module.exports = {
'vendor': {
'scripts': {
'src': [
'bower_components/jquery/dist/jquery.min.js',
'bower_components/lodash/dist/lodash.min.js',
// Moment
'bower_components/moment/min/moment.min.js',
'bower_components/moment/locale/zh-tw.js',
// Ionic & Angular
'bower_components/ionic/js/ionic.bundle.min.js',
'bower_components/ngCordova/dist/ng-cordova.min.js'
// ...
],
'dest': 'www/js',
'output': 'vendor.bundle.js'
},
'styles': {
'src': [
// Mobiscroll
'bower_external/mobiscroll/css/mobiscroll.custom-2.17.0.min.css',
],
'dest': 'www/css',
'output': 'vendor.bundle.css'
}
}
}
}
vendor.js
'use strict';
var config = require('../config');
var gulp = require('gulp');
var gulpif = require('gulp-if');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var postcss = require('gulp-postcss');
var cssnano = require('cssnano');
var handleErrors = require('../util/handleErrors');
var browserSync = require('browser-sync');
var pkg = require('../../package.json');
gulp.task('vendorScripts', function () {
return gulp.src(config.vendor.scripts.src)
.pipe(concat(config.vendor.scripts.output))
.pipe(uglify())
.pipe(gulp.dest(config.vendor.scripts.dest));
});
gulp.task('vendorStyles', function () {
return gulp.src(config.vendor.styles.src)
.pipe(concat(config.vendor.styles.output))
.pipe(postcss([ cssnano() ]))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(config.vendor.styles.dest));
});
gulp.task('vendor', ['vendorScripts', 'vendorStyles']);

Compile using Gulp handlebars partials to single HTML file

I would like to create a gulpfile to compile from partials into a single HTML file. This is my file structure:
| css/
| - main.css
| gulpfile.js
| less/
| - main.less
| index.html
| templates/
| - index.handlebars
| - partials /
| -- header.hbs
| -- footer.hbs
My gulpfile.js looks like this:
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var hbsAll = require('gulp-handlebars-all');
var handlebars = require('handlebars');
var gulpHandlebars = require('gulp-compile-handlebars')(handlebars); //default to require('handlebars') if not provided
var rename = require('gulp-rename');
var less = require('gulp-less-sourcemap');
var autoprefixer = require('gulp-autoprefixer');
var watch = require('gulp-watch');
handlebars.registerPartial('header', '{{header}}'),
handlebars.registerPartial('footer', '{{footer}}')
gulp.task('default', function () {
options = {
partialsDirectory : ['./templates/partials']
}
return gulp.src('templates/index.handlebars')
.pipe(gulpHandlebars( options))
.pipe(rename('index.html'))
.pipe(gulp.dest(''));
});
gulp.task('hbsToHTML', function() {
gulp.src('templates/*.hbs')
.pipe(hbsAll('html', {
context: {foo: 'bar'},
partials: ['templates/partials/*.hbs'],
}))
.pipe(gulp.dest('templates'));
});
gulp.task('less', function () {
gulp.src('./less/*.less')
.pipe(less({
sourceMap: {
sourceMapRootpath: '../less' // Optional absolute or relative path to your LESS files
}
}))
.pipe(gulp.dest('./css'));
});
gulp.task('prefix', function () {
return gulp.src('css/main.css')
.pipe(autoprefixer({
browsers: ['last 2 versions'],
cascade: false
}))
.pipe(gulp.dest('./css'));
});
gulp.task('default', ['hbsToHTML', 'less', 'prefix']);
and my index.handlebars file looks like this:
{{> header}}
<p>Hello </p>
<p>there </p>
{{> footer}}
So, everthing else looks fine, but I can't get the hbsToHTML function to work. Any help is welcome! I know there could be more than a few bugs :(
There's an excellent gulp plugin which does exactly this. You can find it on npm here: https://www.npmjs.com/package/gulp-compile-handlebars
Set the path to your partials using the batch option.
Set the path to your templates using gulp.src
and set the destination using gulp.dest
The example code on the npm page demonstrates this, though in your case you will not need the partials option and you may want to set the ignorePartials to false so that it picks up all the files you have in your partials directory
I figured it out btw and uploaded it to git. Check it.
https://github.com/nikdelig/hbsToHTML
gulp.task('hbsToHTML', function() {
gulp.src('templates/*.hbs')
.pipe(hbsAll('html', {
context: {foo: 'bar'},
partials: ['templates/partials/**/*.hbs'],}))
.pipe(rename('index.html'))
.pipe(htmlmin({collapseWhitespace: true}))
.pipe(gulp.dest(''));
});

Multiple gulp sources and destinations

I am trying to have following directory structure
-- src
|__ app
|__ x.ts
|__ test
|__ y.ts
-- build
|__ app
|__ js
|__ test
|__ js
I want that on "gulp compile", I have my generated js files inside build/app and build/test. i.e. I have multiple sources and multiple destination.
I dont want to create a new gulp target for test one. Following are two various methods which I am trying to accomplish the task
gulp.task('compile', function () {
//path to src/app typescript files
var app_js = gulp.src('./src/app/**/*.ts')
.pipe(tsc(tsProject))
//path to src/test typescript files
var test_js = gulp.src('./src/test/**/*.ts')
.pipe(tsc(tsProject));
return merge([
app_js.js.pipe(gulp.dest('./build/src/app/')),
test_js.js.pipe(gulp.dest('./build/src/test/'))
]);
});
gulp.task('bundle', function () {
var paths = [
{ src: './src/app/**/*.ts', dest: './build/src/app/' },
{ src: './src/test/**/*.ts', dest: './build/src/test/' }
];
var tasks = paths.map(function (path) {
return gulp.src(path.src).pipe(tsc(tsProject)).pipe(gulp.dest(path.dest));
})
return merge(tasks);
});
However, every time, I run "gulp compile" or "gulp bundle", I hit following issues
events.js:141
throw er; // Unhandled 'error' event
^Error: stream.push() after EOF
at readableAddChunk (_stream_readable.js:132:15)
Can somebody tell me that what am I doing wrong here?
NOTE: I tried using both merge-stream and merge2 packages.
Ower! Thanks for your prompt response.
I end up with following solution
gulp.task('compile', function () {
return gulp.src(['src/**/*.ts'] )
.pipe(sourcemaps.init())
.pipe(tsc(tsProject))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('build'));
});"
I have the same project structure in one of my projects and I use the following for the build task:
var tsProject = tsc.createProject({
removeComments : false,
noImplicitAny : false,
target : "ES5",
module : "commonjs",
declarationFiles : false
});
gulp.task("build-source", function() {
return gulp.src(__dirname + "/source/**/**.ts")
.pipe(tsc(tsProject))
.js.pipe(gulp.dest(__dirname + "/build/source/"));
});
var tsTestProject = tsc.createProject({
removeComments : false,
noImplicitAny : false,
target : "ES5",
module : "commonjs",
declarationFiles : false
});
gulp.task("build-test", function() {
return gulp.src(__dirname + "/test/*.test.ts")
.pipe(tsc(tsTestProject))
.js.pipe(gulp.dest(__dirname + "/build/test/"));
});
gulp.task("build", function(cb) {
runSequence("lint", "build-source", "build-test", cb);
});
I'm using two separated tasks because using one tsProject object with multiple sources and multiple destinations can lead to unexpected behavior.
You must create the project outside of the task. You can't use the same project in multiple tasks. Instead, create multiple projects or use a single task to compile your sources. - Source
I also use the following for the bundle task:
gulp.task("bundle-source", function () {
var b = browserify({
standalone : 'inversify',
entries: __dirname + "/build/source/inversify.js",
debug: true
});
return b.bundle()
.pipe(source("inversify.js"))
.pipe(buffer())
.pipe(gulp.dest(__dirname + "/bundled/source/"));
});
gulp.task("bundle-test", function () {
var b = browserify({
entries: __dirname + "/build/test/inversify.test.js",
debug: true
});
return b.bundle()
.pipe(source("inversify.test.js"))
.pipe(buffer())
.pipe(gulp.dest(__dirname + "/bundled/test/"));
});
gulp.task("bundle", function(cb) {
runSequence("build", "bundle-source", "bundle-test", "document", cb);
});
My entire build script is available here. Hope it helps!

Unable to get Jasmine working with basic library

I'm new to using Jasmine and Grunt (and StackOverflow). I'm trying to setup the most basic of projects. However, when I run my grunt task, I get an error that says:
Running "jasmine:testShared" (jasmine) task
Testing jasmine specs via PhantomJS
>> Error: notloaded: Module name "../" has not been loaded yet for context: _. Use require([])
>> http://requirejs.org/docs/errors.html#notloaded at
>> ..\..\C:\Tests\jasmine\_SpecRunner.html:21
>> ..\..\C:\Tests\jasmine\.grunt\grunt-contrib-jasmine\require.js:12 v
>> ..\..\C:\Tests\jasmine\.grunt\grunt-contrib-jasmine\require.js:26 h
>> ..\..\C:\Tests\jasmine\.grunt\grunt-contrib-jasmine\require.js:31
>> ..\..\C:\Tests\jasmine\node_modules\glob\examples\g.js:1
>> Error: notloaded: Module name "../" has not been loaded yet for context: _. Use require([])
>> http://requirejs.org/docs/errors.html#notloaded at
>> ..\..\C:\Tests\jasmine\_SpecRunner.html:21
>> ..\..\C:\Tests\jasmine\.grunt\grunt-contrib-jasmine\require.js:12 v
>> ..\..\C:\Tests\jasmine\.grunt\grunt-contrib-jasmine\require.js:26 h
>> ..\..\C:\Tests\jasmine\.grunt\grunt-contrib-jasmine\require.js:31
>> ..\..\C:\Tests\jasmine\node_modules\glob\examples\usr-local.js:1
>> ReferenceError: Can't find variable: module at
>> ..\..\C:\Tests\jasmine\node_modules\glob\glob.js:37
>> Error caught from PhantomJS. More info can be found by opening the Spec Runner in a browser.
Warning: SyntaxError: Parse error Use --force to continue.
Aborted due to warnings.
I can't figure out what I'm doing wrong. The code for this project can be found here. My file structure looks like this:
/jasmine
/node_modules
/shared
/modules
myModule.js
/tests
/unit
myModule.tests.js
/tasks
/options
jasmine.js
protractor.js
test_task.js
_SpecRunner.html
gruntfile.js
package.json
My package.json file looks like this:
{
"name": "MyApp",
"version": "1.0.0",
"dependencies": {
"async": "~0.9.0",
"glob":"~4.0.3",
"grunt":"~0.4.0",
"grunt-cli":"~0.1.13",
"grunt-contrib-connect":"0.7.1",
"grunt-contrib-jasmine":"~0.6.5",
"grunt-protractor-runner":"1.0.1",
"grunt-start-webdriver":"0.0.2",
"grunt-template-jasmine-requirejs":"0.2.0",
"jasmine-core":"2.0.0",
"jasmine-node":"2.0.0-beta3",
"load-grunt-tasks":"0.2.x",
"lodash":"~2.4.1",
"phantomjs": "1.9.7-14",
"selenium-webdriver":"2.42.1",
"time-grunt":"~0.3.2"
}
}
My gruntfile.js file looks like this:
'use strict';
module.exports = function (grunt) {
var config = {
name: 'MyApp',
pkg: grunt.file.readJSON('package.json'),
baseDir: '.'
};
// load all grunt task details
require('load-grunt-tasks')(grunt);
// show elapsed time at the end
require('time-grunt')(grunt);
// load task definitions
grunt.loadTasks('tasks');
// Utility function to load plugin settings into config
function loadConfig(config,path) {
require('glob').sync('*', {cwd: path}).forEach(function(option) {
var key = option.replace(/\.js$/,'');
// If key already exists, extend it. It is your responsibility to avoid naming collisions
config[key] = config[key] || {};
grunt.util._.extend(config[key], require(path + option)(config,grunt));
});
}
// Merge that object with what with whatever we have here
loadConfig(config,'./tasks/options/');
grunt.loadNpmTasks('grunt-start-webdriver');
grunt.loadNpmTasks('grunt-protractor-runner');
// pass the config to grunt
grunt.initConfig(config);
};
myModule.js looks like this:
'use strict';
var _ = require('lodash');
_.mixin({
'myFunction' : function(s) {
return 'Hello ' + s;
}
});
module.exports = _;
myModule.tests.js looks like this:
'use strict';
describe('myModule', function() {
it('should work', function() {
expect(true).toBe(true);
});
});
test_task.js looks like this:
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.registerTask('test-shared', [
'jasmine:testShared'
]);
};
jasmine.js looks like this:
module.exports = function(config) {
return {
testShared: {
src: "shared/modules/*.js",
options: {
specs: "shared/tests/unit/**.tests.js",
vendor: "node_modules/**/*.js",
template: require('grunt-template-jasmine-requirejs')
}
}
};
};
protractor.js looks like this:
module.exports = function(config) {
return {
testShared: {
options: {
configFile: "shared/tests/unit/config.js"
}
}
};
};
I've spent two days on this. I have no idea what I'm doing wrong. I feel like I've followed the examples online. I feel like there is something stupid I'm overlooking. Can someone please show me what I'm doing wrong?
It's very hard to diagnose without a running example but that error is caused by RequireJS. It happens when you do require('something') without having loaded it. Loading is asynchronous so you either need to do require['lodash'], function(_) { do stuff }. Or the preferred define syntax:
define([
'lodash'
], function(_) {
'use strict';
_.mixin({
myFunction: function(s) {
return 'Hello ' + s;
}
});
return _;
});
With a test you would typically use the same structure and pull in the module you are testing in the define. You would set it up so the path to required files is the same as in the app.
To help more we need a running example.
My colleague made a good boilerplate using grunt/jasmine/requirejs maybe you can get some good practices from there: https://github.com/mderrick/backbone-boilerplate
Your directory structure is quite confusing have you considered simplifying it?
- Use a single Gruntfile.js - don't fragment unless your project is very big
index.html
Gruntfile.js
app/
test/
That is all you really need to get going. In app it could look something like:
app/app.js <-- entry point
app/modules/...

Categories