Rollup bundle using exports instead of module.exports - node.js

I have a library I am bundling using rollup and this is a section from the rollup.config.js file:
export default {
input: `src/${libraryName}.ts`,
output: [
{ file: pkg.main, name: camelCase(libraryName), format: 'cjs', sourcemap: true },
{ file: pkg.module, format: 'es', sourcemap: true },
],
....
}
It generates two files dist/libname.umd.js and dist/libname.es5.js. I have confirmed from putting a console.log statement in both the files that using require('libname') loads the dist/libname.umd.js. However, the following line:
var x = require('libname').X
console.log(x) // This is undefined
prints undefined. So, I tried to edit the dist/libname.umd.js file manually and at the bottom of the file I saw:
exports.X = X;
with the overall variable X being bundled somewhere above in the file. I modified this to:
module.exports.X = X;
and then it seems to work. I am a bit new to node/js so I wasn't sure if it this is the way to be exporting modules, but on reading a blog post (http://www.hacksparrow.com/node-js-exports-vs-module-exports.html) it turns out both of them should be fine? I am still a bit unclear on this one though.
Also, when I simply did this:
console.log(require('libname')
it prints [Function: uniqSetWithForEach] and console.log(require('libname')()) prints [].
EDIT So for the time being, just so that I can continue my work I have modified rollup.config.ts to add an outro:
export default {
...
output: [
{ file: pkg.main, name: camelCase(libraryName), format: 'cjs',
sourcemap: true,
outro: 'module.exports = Object.assign({}, module.exports, exports)'
}
]
...
}
and this seems to do it for now, but I'm pretty sure it's not a clean solution.

Related

Dom_munger issue with Node 7.7.3 - Path must be a string

I'm trying to update an application to support Node -v 7.7.3. But when I am running the grunt task dom_munger as per below:
dom_munger:{
read: {
options: {
read:[
{selector:'script[data-concat!="false"]',attribute:'src',writeto:'appjs', isPath: true},
{selector:'link[rel="stylesheet"][data-concat!="false"]',attribute:'href',writeto:'appcss'}
]
},
src: 'app/index.html'
}
}
I receive error:
Warning: Path must be a string. Received [ 'app/index.html' ] Use --force to continue.
I wonder if there is a way to rewrite above grunt task or if there might be a good alternative to dom_munger. Any help would be appreciated.
Per the grunt-dom-munger Github:
When isPath is true, the extracted values are assumed to be file
references and their path is made relative to the Gruntfile.js rather
than the file they're read from.
Try removing the isPath property, or altering it to match the path from your Gruntfile to the index.html file.
Remove isPath: true, and make sure that path in src attribute relative to the Gruntfile.js rather than the file they're read from.
If needs make a replace in path:
dom_munger: {
replacePath: {
options: {
callback: function($, file){
var scripts = $('script[data-concat!="false"]');
// NOTE: path is made relative to the Gruntfile.js rather than the file they're read from
for(var i=0, s, il=scripts.length; i<il; i++){
s = scripts[i];
if(s.attribs.src){
s.attribs.src = s.attribs.src.replace('../', '');
}
}
}
},
src: 'temp/index.html'
},
read: {
options: {
read: [
{selector:'script[data-concat!="false"]',attribute:'src',writeto:'appjs'},
{selector:'link[rel="stylesheet"][data-concat!="false"]',attribute:'href',writeto:'appcss'}
]
},
src: 'temp/index.html'
}
}
Thanks you! But this only seems to work if the Grunt and Index are in the same folder structure. My structure looks like this:
- /app
-index.html
- gruntfile.js
And without the attribute 'isPath' the dom_munger will look for js files in the same directory as where the Gruntfile is places.

GitHub Electron: build menu in required file

I am seasoned in JavaScript, but very new to node and to Electron. I am trying to piece the technique together from code samples and what documentation I can find.
I would like to include my menu code in a separate file. The main code is in a file called renderer.js and the menu code in one called menu.js. A simple example:
// renderer.js
function doit() {
alert('hello');
}
module.exports.doit=doit; // Added
var q=require('./menu');
var q=require('./menu');
// menu.js
var template = [
{
label: 'Test',
submenu: [
{
label: 'Something',
click() {
doit();
}
}
]
}
];
const {remote} = require('electron');
const renderer=require('./renderer'); // Added
const {Menu, MenuItem} = remote;
const app=remote.app; // Addes
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
The menu is created, but when selecting the menu item, I get the message: Uncaught ReferenceError: doit is not defined.
I understand the meaning of the message, and clearly variables are not passed between the files.
How can I accomplish this?
Update: I have added some lines in the sample incorporate the accepted answer below. This now works.
Clearly I did not understand the meaning of require(). It strikes me as odd that each file can require the other. Anyway …
Thanks
If you wish to access symbols defined in one Node module from another you have to export them via module.exports:
// renderer.js
function doit() {
// ...
}
module.exports.doit = doit;
And load the module via require:
// menu.js
const { doit } = require('./renderer');
// OR: const doit = require('./renderer').doit;
var template = [
{
label: 'Test',
submenu: [
{
label: 'Something',
click() {
doit();
}
}
]
}
];
This and much more is covered in the Node API docs.
I am trying to solve the same challenge. Currently I am looking into this:
https://github.com/ragingwind/electron-menu-loader
He basically adds a property 'event' and replaces that with an event handler.

Require, Knockout and pager are Undefined TypeError

I have the following main:
requirejs.config({
paths:{
'text':'../vendor/js/text.min',
'jquery':"../vendor/js/jquery.min",
'boostrap':"../vendor/js/bootstrap.min",
'ko':"http://knockoutjs.com/downloads/knockout-3.4.0.debug",
'pager':"../vendor/js/pager",
'imageGroupsVm':'../js/viewModels/imageGroupsViewModel',
'panelVm':'../js/viewModels/panelViewModel',
'compMessage':'../js/components/message',
'extBooleanToggle':'../js/extenders/booleanToggle'
},
shim:{
'bootstrap':['jquery'],
'pager':['ko'],
},
waitSeconds: 200,
});
define(['jquery','ko','pager','panelVm'],function($,ko,pager,panelVm)
{
pager.extendWithPage(panelVm);
ko.applyBindings(panelVm);
pager.start();
});
But for some reason I get these 2 error messages:
TypeError: ko is undefined
Stack trace:
pagerJsModule#http://localhost/symphotest/assets/vendor/js/pager.js:150:9
#http://localhost/symphotest/assets/vendor/js/pager.js:1506:20
newContext/context.execCb#http://localhost/symphotest/assets/vendor/js/require.min.js:1690:24
newContext/Module.prototype.check#http://localhost/symphotest/assets/vendor/js/require.min.js:865:43
newContext/Module.prototype.enable/</<#http://localhost/symphotest/assets/vendor/js/require.min.js:1140:29
bind/<#http://localhost/symphotest/assets/vendor/js/require.min.js:131:20
newContext/Module.prototype.emit/<#http://localhost/symphotest/assets/vendor/js/require.min.js:1190:21
each#http://localhost/symphotest/assets/vendor/js/require.min.js:56:31
newContext/Module.prototype.emit#http://localhost/symphotest/assets/vendor/js/require.min.js:1189:17
newContext/Module.prototype.check#http://localhost/symphotest/assets/vendor/js/require.min.js:940:25
newContext/Module.prototype.enable#http://localhost/symphotest/assets/vendor/js/require.min.js:1177:17
newContext/Module.prototype.init#http://localhost/symphotest/assets/vendor/js/require.min.js:783:21
callGetModule#http://localhost/symphotest/assets/vendor/js/require.min.js:1204:17
newContext/context.completeLoad#http://localhost/symphotest/assets/vendor/js/require.min.js:1604:1
newContext/context.onScriptLoad#http://localhost/symphotest/assets/vendor/js/require.min.js:1711:21
require.min.js:900:37
TypeError: pager is undefined
Stack trace:
#http://localhost/symphotest/assets/js/panel-main.js:65:5
newContext/context.execCb#http://localhost/symphotest/assets/vendor/js/require.min.js:1690:24
newContext/Module.prototype.check#http://localhost/symphotest/assets/vendor/js/require.min.js:865:43
newContext/Module.prototype.enable/</<#http://localhost/symphotest/assets/vendor/js/require.min.js:1140:29
bind/<#http://localhost/symphotest/assets/vendor/js/require.min.js:131:20
newContext/Module.prototype.emit/<#http://localhost/symphotest/assets/vendor/js/require.min.js:1190:21
each#http://localhost/symphotest/assets/vendor/js/require.min.js:56:31
newContext/Module.prototype.emit#http://localhost/symphotest/assets/vendor/js/require.min.js:1189:17
newContext/Module.prototype.check#http://localhost/symphotest/assets/vendor/js/require.min.js:940:25
newContext/Module.prototype.enable/</<#http://localhost/symphotest/assets/vendor/js/require.min.js:1140:29
bind/<#http://localhost/symphotest/assets/vendor/js/require.min.js:131:20
newContext/Module.prototype.emit/<#http://localhost/symphotest/assets/vendor/js/require.min.js:1190:21
each#http://localhost/symphotest/assets/vendor/js/require.min.js:56:31
newContext/Module.prototype.emit#http://localhost/symphotest/assets/vendor/js/require.min.js:1189:17
newContext/Module.prototype.check#http://localhost/symphotest/assets/vendor/js/require.min.js:940:25
newContext/Module.prototype.enable#http://localhost/symphotest/assets/vendor/js/require.min.js:1177:17
newContext/Module.prototype.init#http://localhost/symphotest/assets/vendor/js/require.min.js:783:21
callGetModule#http://localhost/symphotest/assets/vendor/js/require.min.js:1204:17
newContext/context.completeLoad#http://localhost/symphotest/assets/vendor/js/require.min.js:1604:1
newContext/context.onScriptLoad#http://localhost/symphotest/assets/vendor/js/require.min.js:1711:21
require.min.js:900:37
Furtermore The panelViewModel.js contains:
define(['ko','imageGroupsVm','compMessage'],function(ko,ImageGroupsVM,loginViewModel)
{
var image_groups=new ImageGroupsVM();
return {'imageGroups':image_groups};
});
And the ImageGroupsViewModel Contains:
define(['ko','jquery'],function(ko,$)
{
console.log(ko);
return function imageGroupsViewModel()
{
var self=this;
self.albums=ko.observableArray();
self.init=function()
{
self.albums([]);
self.fetchData();
}
self.fetchData=function()
{
console.log("Data Fetched");
};
function Album(data)
{
}
};
})
All the JS files that I have are: (note that tin vendor classes are the external libraries I load)
I managed to fix it by replacing the 'ko' with 'knockout' whenever is required.
More specifically on main (the file you include in data-main on your html)
The following line:
'ko':"http://knockoutjs.com/downloads/knockout-3.4.0.debug",
Changed into:
'knockout':"http://knockoutjs.com/downloads/knockout-3.4.0.debug",
I Included on shim:
'pager':['knockout'],
And the
define(['jquery','ko','pager','panelVm'],function($,ko,pager,panelVm)
Changed into
define(['jquery','knockout','pager','panelVm'],function($,ko,pager,panelVm)
Therefore my main is:
requirejs.config({
paths:{
'text':'../vendor/js/text.min',
'knockout':"https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min",
'pager':"../vendor/js/pager.min",
'jquery':"../vendor/js/jquery.min",
'boostrap':"../vendor/js/bootstrap.min",
'imageGroupsVm':'../js/viewModels/imageGroupsViewModel',
'panelVm':'../js/viewModels/panelViewModel',
'compMessage':'../js/components/message',
'extBooleanToggle':'../js/extenders/booleanToggle'
},
shim:{
'pager':['knockout'],
'bootstrap':['jquery'],
},
waitSeconds: 200,
});
define(['jquery','knockout','pager','panelVm'],function($,ko,pager,panelVm)
{
pager.extendWithPage(panelVm);
ko.applyBindings(panelVm);
pager.start();
});
Also on my other javascript files on my project that are loaded with require I changed the line:
define(['ko',...,'other_lib'],function(ko,....,other_lib)
With:
define(['knockout',...,'other_lib'],function(ko,....,other_lib)
Note:
I also changed theese lines on other main.js that I load with require on another pages:
'ko':"http://knockoutjs.com/downloads/knockout-3.4.0.debug",
Changed into:
'knockout':"http://knockoutjs.com/downloads/knockout-3.4.0.debug",
I did this in order to load all the modules I make by using require.

How to make separate report for different specification files in protractor?

How can we make separate reports for different specification files in protractor?
multiCapabilities: [{
'browserName': 'chrome'
}, {
'browserName': 'firefox'
}
{
'browserName': 'internet explorer'
}],
framework: 'jasmine',
specs: ['TC_2.js','TC_3.js'],
Currently my code will generate HTML report for "chrome" execution in first iteration.When it go next iteration,it will generate report for "FF".In 3rd iteration it will generate report for "IE".However at the end I am getting last iteration(i.e 3rd )internet explorer HTML report at base location.Because this last iteration replacing the report of previous iterations.
Is there a way to get all 3 reports?(i.e Chrome,FF and IE reports)
protractor-html-screenshot-reporter is the report I am using.
Following is my code:
onPrepare: function() {
beforeEach(function() {
browser.driver.manage().window().setSize(1280, 1024);
});
jasmine.getEnv().addReporter(new HtmlReporter({
baseDirectory: 'D:/Manoj/TestReport3/',
docTitle: 'Test Case Execution Details',
docName: 'BYTestReport.html',
//Meta builder
metaDataBuilder: function(spec, descriptions, results, capabilities){
var metaData = {
description: descriptions.join('|'),
passed: results.passed(),
os: 'Windows 7',
browser: {
name: capabilities.caps_.browserName
, version: capabilities.caps_.version
}
};
if(results.items_.length > 0) {
var result = results.items_[0];
metaData.message = result.message;
metaData.trace = result.trace.stack;
}
return metaData;
} // Meta Builder ends
}));
},
Yes, I use browserName as folder name for html report, and jsons, and pngs:
Inside onPrepare: function(){
browser.getCapabilities().then(function (cap) {
console.log(cap);
browser.browserName = cap.caps_.browserName;
jasmine.getEnv().addReporter(new HtmlReporter({
baseDirectory: 'target/'+browser.browserName+'/angular-test-result/',
takeScreenShotsOnlyForFailedSpecs: true,
preserveDirectory: false
}));
});
and remove addReporter from where you already have it
Your code updated to protractor-html-screenshot-reporter:
var HtmlReporter = require('protractor-html-screenshot-reporter');
onPrepare: function() {
browser.driver.manage().window().setSize(1280, 1024);
browser.getCapabilities().then(function (cap) {
console.log(cap);
browser.browserName = cap.caps_.browserName;
jasmine.getEnv().addReporter(new HtmlReporter({
baseDirectory: 'target/'+browser.browserName+'/angular-test-result/',
takeScreenShotsOnlyForFailedSpecs: true,
preserveDirectory: false
}));
});
}
BTW you have to install reporter: npm install protractor-html-screenshot-reporter --save-dev
You can create different protractor config files for specific specs and trigger those specific e2e suits with different command specifying in package.json passing the config file as parameter.
ex: "specifice2e": "\"ng e2e --protractorConfig=e2e\specificprotractor.conf.js "
And in config file you can mention the folder name where you want to generate seperate report.

require js defining modules in html script tags

I am trying to define a module for the initual configuration options of my app inside an script tag in my html. but I get the following error:
Error: Module name "options" has not been loaded yet for context: _. Use require([]) http://requirejs.org/docs/errors.html#notloaded
here is the html:
<script src="Scripts/require.js" data-main="/Recruiter/temp-search/App/main"></script>
<script>
define('options',['jquery'],function($) {
return options = {
salesPhoneNumber : '#ConfigurationManager.AppSettings.Get("SalesPhoneNumber")',
saleInfoMessage : "To access Temp Search candidate details, please call our team on " + salesPhoneNumber,
subscriptionInfo : #Html.Raw(new JavaScriptSerializer().Serialize(Model.AccessInfo ?? null)),
questionProLink: src="#(Request.Url.Scheme)://www.questionpro.com/a/TakeSurvey?id=#(Model.IsRecCon ? AppSettings.SurveyRecConId : AppSettings.SurveyOthersId)&custom1=#Model.RecruiterEmail&custom2=#Model.RecruiterId",
surveyEnabled: '#AppSettings.FlexSurveyEnabled',
whatsNewUrl: '#AppSettings.UrlWhatsNew',
salesPhoneNumber:salesPhoneNumber,
showSaleInfo: '#ViewBag.ShowSaleInfo',
fileDownloadFailCookieName:'#AppSettings.FileDownloadFail',
urls: {
signInUrl: '#string.Format("https://{0}/recruiter/account/signIn", Url.RequestContext.HttpContext.Request.Url.Host)',
signInTempsHome: '/recruiter/temp-search/home',
signInTempsSearch: '/recruiter/temp-search/api/temps',
checkAvailabilityUrl: '/recruiter/temp-search/api/availability',
searchUrl: '/recruiter/temp-search/api/temps/search',
accesslimitUrl: '/recruiter/temp-search/api/ecruiters/accessinfo',
previewUrl: '/recruiter/temp-search/api/temps/preview'
},
elements: {
signInRegisterDialog: $("#signInRegisterDialog"),
noSubscriptionDialog: $("#noSubscriptionDialog"),
searchForm: $("#searchForm"),
searchKeywords: $("#Keywords"),
searchLocation: $("#Location"),
searchRadius: $("#Radius"),
searchSortBy: $("#sortBy"),
searchTemp: $("#Temporary"),
searchContract: $("#Contract"),
searchPayRateFrom: $("#PayRateFrom"),
searchPayRateTo: $("#PayRateTo"),
searchAvailability: $("#AvailabilityConfirmed"),
locationErrorMsg: $("#locationErrorMsg"),
checkAll: $(".checkAll"),
checkCandidate: $(".checkCandidate"),
availability: {
availabilityBtn: $("#availabilityBtn"),
availabilityDialog: $("#availabilityDialog"),
additionalInformation: $("#AdditionalInformation"),
jobPosition: $("#JobPosition"),
jobLocation: $("#JobLocation"),
payRate: $("#JobPayRateFrom"),
payRateTo: $("#JobPayRateTo"),
startOn: $("#StartOnDate"),
duration: $("#Duration"),
checkAvailabilityForm: $("#checkAvailabilityForm"),
availabilityLocation: $("#checkAvailabilityForm #JobLocation"),
candidateIds: $("#CandidateIds"),
tempJobId: $("#TempJobId"),
msgPanel: $("#msgPanel"),
msg: $(".msg"),
errorAvailability: $("#availabilityError"),
availabilityConfirmationDialog: $("#availabilityConfirmationDialog"),
infoBubbleMessage : $("#infoBubbleMessage"),
availabilityConfirmationMsg: $("#availabilityConfirmationDialog .msgDialog"),
downloadInfoLink : $("#downloadInfoLink")
},
preview: {
previewBtn: $('.previewBtn')
},
messagePanel: $("#messagePanel")
},
minWageRate : #Constants.Range.ApprenticeshipsPerHourMin,
authentication : #(Request.IsAuthenticated.ToString().ToLower()),
minDate: '#String.Format("{0:yyyy/MM/dd}", DateTime.Now)',
pageInfo: {
number: #Model.Results.PageNumber,
size: #Model.Results.PageSize,
resultsCount: #Model.TotalResultsCount
},
criteria : #Html.Raw(new JavaScriptSerializer().Serialize(Model.Criteria)),
remainingAccessLimit: #Model.AccessInfo.Remaining,
totalAccessLimit: #Model.AccessInfo.Limit,
availableCandidates: #Model.AvailableCandidates,
candidates: #Html.Raw(new JavaScriptSerializer().Serialize(Model.Results ?? Model.Results.ToJSON()))
};
})
</script>
The problem is not with the code you show in your question but with how you ask RequireJS to load your module. The error message you show happens when you do a require call of this form:
var foo = require('foo');
This kind of require call does not work unless foo is already loaded, and to ensure it is already loaded you can manually load it yourself, or you can have RequireJS do it for you. However, to get RequireJS to do it for you, you need to write your code in a certain way. If you want a module to use foo and you want to use the require above then, you should do:
define(function (require) {
var foo = require('foo');
...
});
Or if you need to use module and exports, the callback can be function (require, exports, module) {....
Also, you should perform the following operations in this order:
Load RequireJS.
Execute define('options', ....
Then and only then start loading your application.
This means removing data-main and using an explicit require call after define('options'.

Resources