I have the main function to export and the jQuery adaptor in the same file. And I would like to keep them this way.
Is there a way with rollup.js to create the bundle file compatible with AMD, CommonJS and Browsers?
Right now I have this test file:
//src/foo.js
export default function(){
function initialise() {
var TEST = {};
TEST.version = '1.0.0';
TEST.hello = function(){
console.log("hello man!!");
};
return TEST;
}
//jQuery adapter
(function($){
$.fn.demo = function(options) {
$.fn.demo.test = 'test';
};
})(jQuery);
return initialise;
};
And I tried using this rollup config:
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'umd',
globals: {
$: '$'
}
}
};
However I can't seem to have access to $.fn.demo:
// src/main.js
import jQuery from 'jQuery';
import pepe from './foo.js';
console.log(jQuery); //<--- undefined
console.log($); //<--- undefined
console.log("-- JS--");
console.log(pepe); //<---- working fine
console.log("-- $.fn.demo --");
console.log($.fn.demo); //<--- undefined
Note that in your main.js file pepe is a function (one which you exported from foo) and you didn't call it hence $.fn.demo is undefined. You must call pepe(); in order for you adapter to be executed.
See also how to tell Rollup that jquery is external and the jquery module ID equates to the global $ variable.
Related
I use Webpack as a package manager and ES6. Looks like an imported module is not correctly evaluated with eval.
How to eval a string using the imported Module ?
Code:
In a global scope:
<script type="text/javascript">
var tableDefinition = '{ value: "myvalue", myfunction: (v) => { return DateFormat.format(v) }}';
</script>
In my module:
import DateFormat from "~modules/DateFormat"; // a module helper written by me
class GeneriClass {
constructor() {
DateFormat.init();
let columns = eval(tableDefinition); // this code retrieves 'DateFormat' not defined
}
}
The error on eval is: "'DateFormat' not defined!"
there are three files :
a.js
b.js
token.js
I need to use the same token in a.js and b.js, How do I achieve that? for example, set token in a.js and get token in b.js
I am using a singleton but it does not work :(
token.js
class Token {
private static instance: Token
private _hash = 'default-hash'
private constructor() {
}
static getInstance() {
if (!Token.instance) {
Token.instance = new Token()
}
return Token.instance
}
//setter and getter for _hash
}
export default Token
The module.exports or exports is a special object which is included in every JS file in the Node.js application by default. module is a variable that represents current module and exports is an object that will be exposed as a module. So, whatever you assign to module.exports or exports, will be exposed as a module.
Examples: Export Literals
File: message.js
module.exports = 'Hello world';
Now, import this message module and use it as shown below.
File: app.js
var msg = require('./messages.js');
console.log(msg);
Example: Export Object
message.js
exports.SimpleMessage = 'Hello world';
//or
module.exports.SimpleMessage = 'Hello world';
In the above example, we have attached a property "SimpleMessage" to the exports object. Now, import and use this module as shown below.
app.js
var msg = require('./messages.js');
console.log(msg.SimpleMessage);
Example: Export Function
You can attach an anonymous function to exports object as shown below.
log.js
module.exports = function (msg) {
console.log(msg);
};
Now, you can use the above module as below.
app.js
var msg = require('./log.js');
msg('Hello World');
I am trying to use a third party Node module in an angular 2+ project.
installed with npm install --save ModuleName
The function in question is in a file named Foo.js and looks like this:
var foo = function(param1, param2) {
...
this.init();
}
foo.protoype = {
constructor: foo,
init: function(){
...
},
...
}
module.exports = foo;
index.js for the node module looks like:
var ModuleName = require("./src/ModuleName");
ModuleName.foo = require("./src/Foo");
module.exports = ModuleName;
I am trying to use the module in a Directive:
import { Directive, OnInit } from '#angular/core';
import { ModuleName } from "ModuleName"
#Directive({
selector: '[customDirective]'
})
export class CustomDirective implements OnInit {
constructor() {
...
}
ngOnInit() {
let poorlyNamedVariable = ModuleName.foo(param1, param2);
}
}
When foo is called it produces ERROR TypeError: this.init is not a function
console.log(this) in foo shows an instance of ModuleName which, in turn, has an instance of foo, which has a prototype where init is defined.
I suspect the problem stems from some sort of scoping issue, but am still too new to both Angular and Node to untangle the mess.
Use import * as ModuleName from "ModuleName" for CommonJS modules.
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
I'm setting up ES6 unit tests in my project and I am having some trouble making them work with libraries. I thought I'd use jQuery just as a test to try and make it work. Without libraries, the tests work.
Note that jQuery is imported into my main.js file so it is available throughout the project.
My JS file looks like this:
class Test {
constructor(options) {
this.init();
}
init() {
$('.test-div').addClass('test');
}
sayHello() {
return 'hello world!';
}
}
export default Test;
And the test looks like this:
import jsdom from 'mocha-jsdom';
import chai from 'chai';
import Test from './test';
chai.should();
describe('Frequency', () => {
var $;
jsdom();
before(() => {
$ = require('jquery');
})
it('should output hello world', () => {
const test = new Test();
test.sayHello().should.equal('hello world!');
});
});
If I remove the init() function, the test works. However, the before function doesn't seem to import jQuery for the test. The error I receive in the console is as follows:
ReferenceError: $ is not defined
at Frequency.init
I copied your code and got it to work by modifying the before hook to:
before(() => {
$ = require('jquery');
global.$ = $;
});
If you read mocha-jsdom's documentation you'll see that it puts in the global space symbols like window and document. When you load jquery, it finds window and adds itself as window.$. In a browser, this also makes $ visible in the global space because window is the global space. In Node, however, the global space is global, and so you have to put $ in it yourself.
You need to declare global variables in a custom setup.js:
package.json:
"scripts": {
"unit": "mocha-webpack --webpack-config webpack.test.js test/unit/*.spec.js --require test/setup.js"
},
or if you don't use webpack:
"scripts": {
"unit": "mocha test/unit/*.spec.js --require test/setup.js"
},
test/setup.js:
let jsdom = require('jsdom-global')();
let jQuery = require("jquery");
global.jQuery = jQuery;
global.$ = jQuery;
//https://github.com/vuejs/vue-cli/issues/2128
window.Date = Date;
Then you can use them as usual in your test scripts.