RequireJS import documentation - requirejs

Im using in WebStorm editor. My project is using RequireJS with AMD. There is an example of code:
dep.js
define([], function () {
var exports = {
helloWorld: function() {
console.log("Hello world");
}
};
return exports;
});
primary.js
define(['dep'], function (dep) {
var exports = {
sayHello: function() {
dep.helloWorld();
}
};
return exports;
});
How to document properly exports (this mainly described in other answers) and (important!) imports of such AMD modules, so WebStorm can have proper type hints on imported deps (like a "dep" variable in this example).

According to AMD howto, it should be smth like
/**
* #module dep
*/
define([], function() {
/**
* #constructor
* #alias module:dep
*/
var exports = {
helloWorld: function() {
console.log("Hello world");
}
};
return exports;
});

Related

RequireJS + Mocha + JSDom + Node -> Shim config not supported in Node

I'm trying to setup a Mocha testing framework using JSDom with RequireJS. Because I'm running the test on node instead of using a browser (since I'm using JSDom), all the non AMD modules doesn't seem to be imported and is throwing Shim config not supported in Node. Does anyone know how I can export those modules to AMD or what the right approach is? (aka what I'm doing wrong)
Example of my set-up
Component.js
define(["jquery", "non_AMD_Module", ... ], function($, NonAMDModule, ...) {
let component = {
...
foo = () => {
NonAMDModule.bar();
};
};
return component;
});
Component.test.js
const requirejs = require('requirejs');
const { JSDOM } = require('jsdom');
requirejs.config({
baseUrl: "dist/app",
paths: {
jquery: "lib/jquery",
component: "path_to_component",
non_AMD_Module: "path_to_module"
},
shim: {
non_AMD_Module: { exports: "non_AMD_Module" } // This doesn't work
}
});
const { window } = new JSDOM("<html></html>");
global.window = window;
global.document = window.document;
global.$ = requirejs('jquery');
const Component = requireJS('component');
describe('test', () => {
it('is a simple test', () => {
const testComponent = new Component();
testComponent.foo();
}
});
When I run the test suite, I get:
Mocha Exploded!
TypeError: Cannot read property 'bar' of undefined
running r.js -convert "path_to_module" did not work for this module
Looking at the source code for jQuery, I found that there's this boiler-plate coded that exports it to AMD.
This can be added at the bottom of the non-AMD-module in order to export it to an AMD module accessible by RequireJS
if ( typeof define === "function" && define.amd ) {
define([], function {
return non_AMD_Module;
});
}
Other Resources:
Shim a module in Require.js that uses module.exports possible?
https://github.com/requirejs/requirejs/wiki/Updating-existing-libraries#anon

Electron / NodeJS and application freezing on setInterval / async code

I'm working on an electron application that performs a screenshot capture every 3 seconds with the electron api, and writes it to a given target path. I've set up a separate BrowserWindow where the capturing code runs in (see code structure below) a setInterval() "loop", but whenever the capture happens, the app freezes for a moment. I think it is the call to source.thumbnail.toPng() or writeScreenshot() method in the file ScreenCapturer.jshtml.js.
I set up this structure as I though this was the way to go, but apparently this is not. WebWorkers won't help me either as I need node modules such as fs, path and desktopCapturer (from electron).
How would one do this type of task without blocking the main thread every time the interval code (as seen in file ScreenCapturer.jshtml.js) runs (because I thought the renderer processes were separate processes?)
My code as reference
main.js (main process)
// all the imports and other
// will only show the import that matters
import ScreenCapturer from './lib/capture/ScreenCapturer';
app.on('ready', () => {
// Where I spawn my main UI
mainWindow = new BrowserWindow({...});
mainWindow.loadURL(...);
// Other startup stuff
// Hee comes the part where I call function to start capturing
initCapture();
});
function initCapture() {
const sc = new ScreenCapturer();
sc.startTakingScreenshots();
}
ScreenCapturer.js (module used by main process)
'use strict';
/* ******************************************************************** */
/* IMPORTS */
import { app, BrowserWindow, ipcMain } from 'electron';
import url from 'url';
import path from 'path';
/* VARIABLES */
let rendererWindow;
/*/********************************************************************///
/*///*/
/* ******************************************************************** */
/* SCREENCAPTURER */
export default class ScreenCapturer {
constructor() {
rendererWindow = new BrowserWindow({
show: true, width: 400, height: 600,
'node-integration': true,
webPreferences: {
webSecurity: false
}
});
rendererWindow.on('close', () => {
rendererWindow = null;
});
}
startTakingScreenshots(interval) {
rendererWindow.webContents.on('did-finish-load', () => {
rendererWindow.openDevTools();
rendererWindow.webContents.send('capture-screenshot', path.join('e:', 'temp'));
});
rendererWindow.loadURL(
url.format({
pathname: path.join(__dirname, 'ScreenCapturer.jshtml.html'),
protocol: 'file:',
slashes: true
})
);
}
}
/*/********************************************************************///
/*///*/
ScreenCapturer.jshtml.js (the thml file loaded in the renderer browser window)
<html>
<body>
<script>require('./ScreenCapturer.jshtml.js')</script>
</body>
</html>
ScreenCapturer.jshtml.js (the js file loaded from the html file in the renderer process)
import { ipcRenderer, desktopCapturer, screen } from 'electron';
import path from 'path';
import fs from 'fs';
import moment from 'moment';
let mainSource;
function getMainSource(mainSource, desktopCapturer, screen, done) {
if(mainSource === undefined) {
const options = {
types: ['screen'],
thumbnailSize: screen.getPrimaryDisplay().workAreaSize
};
desktopCapturer.getSources(options, (err, sources) => {
if (err) return console.log('Cannot capture screen:', err);
const isMainSource = source => source.name === 'Entire screen' || source.name === 'Screen 1';
done(sources.filter(isMainSource)[0]);
});
} else {
done(mainSource);
}
}
function writeScreenshot(png, filePath) {
fs.writeFile(filePath, png, err => {
if (err) { console.log('Cannot write file:', err); }
return;
});
}
ipcRenderer.on('capture-screenshot', (evt, targetPath) => {
setInterval(() => {
getMainSource(mainSource, desktopCapturer, screen, source => {
const png = source.thumbnail.toPng();
const filePath = path.join(targetPath, `${moment().format('yyyyMMdd_HHmmss')}.png`);
writeScreenshot(png, filePath);
});
}, 3000);
});
I walked away from using the API's delivered by electron. I'd recommend using desktop-screenshot package -> https://www.npmjs.com/package/desktop-screenshot. This worked cross platform (linux, mac, win) for me.
Note on windows we need the hazardous package, because otherwise when packaging your electron app with an asar it won't be able to execute the script inside desktop-screenshot. More info on the hazardous package's page.
Below is how my code now roughly works, please don't copy/paste because it might not fit your solution!! However it might give an indication on how you could solve it.
/* ******************************************************************** */
/* MODULE IMPORTS */
import { remote, nativeImage } from 'electron';
import path from 'path';
import os from 'os';
import { exec } from 'child_process';
import moment from 'moment';
import screenshot from 'desktop-screenshot';
/* */
/*/********************************************************************///
/* ******************************************************************** */
/* CLASS */
export default class ScreenshotTaker {
constructor() {
this.name = "ScreenshotTaker";
}
start(cb) {
const fileName = `cap_${moment().format('YYYYMMDD_HHmmss')}.png`;
const destFolder = global.config.app('capture.screenshots');
const outputPath = path.join(destFolder, fileName);
const platform = os.platform();
if(platform === 'win32') {
this.performWindowsCapture(cb, outputPath);
}
if(platform === 'darwin') {
this.performMacOSCapture(cb, outputPath);
}
if(platform === 'linux') {
this.performLinuxCapture(cb, outputPath);
}
}
performLinuxCapture(cb, outputPath) {
// debian
exec(`import -window root "${outputPath}"`, (error, stdout, stderr) => {
if(error) {
cb(error, null, outputPath);
} else {
cb(null, stdout, outputPath);
}
});
}
performMacOSCapture(cb, outputPath) {
this.performWindowsCapture(cb, outputPath);
}
performWindowsCapture(cb, outputPath) {
require('hazardous');
screenshot(outputPath, (err, complete) => {
if(err) {
cb(err, null, outputPath);
} else {
cb(null, complete, outputPath);
}
});
}
}
/*/********************************************************************///

running e2e testing with aurelia cli

I'm trying to implement a few e2e tests in my aurelia-cli app. I've tried looking for docs or blogs but haven't found anything on e2e setup for the cli. I've made the following adjustments to the project.
first I added this to aurelia.json
"e2eTestRunner": {
"id": "protractor",
"displayName": "Protractor",
"source": "test/e2e/src/**/*.ts",
"dist": "test/e2e/dist/",
"typingsSource": [
"typings/**/*.d.ts",
"custom_typings/**/*.d.ts"
]
},
Also added the e2e tasks on aurelia_project/tasks:
e2e.ts
import * as project from '../aurelia.json';
import * as gulp from 'gulp';
import * as del from 'del';
import * as typescript from 'gulp-typescript';
import * as tsConfig from '../../tsconfig.json';
import {CLIOptions} from 'aurelia-cli';
import { webdriver_update, protractor } from 'gulp-protractor';
function clean() {
return del(project.e2eTestRunner.dist + '*');
}
function build() {
var typescriptCompiler = typescriptCompiler || null;
if ( !typescriptCompiler ) {
delete tsConfig.compilerOptions.lib;
typescriptCompiler = typescript.createProject(Object.assign({}, tsConfig.compilerOptions, {
// Add any special overrides for the compiler here
module: 'commonjs'
}));
}
return gulp.src(project.e2eTestRunner.typingsSource.concat(project.e2eTestRunner.source))
.pipe(typescript(typescriptCompiler))
.pipe(gulp.dest(project.e2eTestRunner.dist));
}
// runs build-e2e task
// then runs end to end tasks
// using Protractor: http://angular.github.io/protractor/
function e2e() {
return gulp.src(project.e2eTestRunner.dist + '**/*.js')
.pipe(protractor({
configFile: 'protractor.conf.js',
args: ['--baseUrl', 'http://127.0.0.1:9000']
}))
.on('end', function() { process.exit(); })
.on('error', function(e) { throw e; });
}
export default gulp.series(
webdriver_update,
clean,
build,
e2e
);
and the e2e.json
{
"name": "e2e",
"description": "Runs all e2e tests and reports the results.",
"flags": []
}
I've added a protractor.conf file and aurelia.protractor to the root of my project
protractor.conf.js
exports.config = {
directConnect: true,
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
//seleniumAddress: 'http://0.0.0.0:4444',
specs: ['test/e2e/dist/*.js'],
plugins: [{
path: 'aurelia.protractor.js'
}],
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000
}
};
aurelia.protractor.js
/* Aurelia Protractor Plugin */
function addValueBindLocator() {
by.addLocator('valueBind', function (bindingModel, opt_parentElement) {
var using = opt_parentElement || document;
var matches = using.querySelectorAll('*[value\\.bind="' + bindingModel +'"]');
var result;
if (matches.length === 0) {
result = null;
} else if (matches.length === 1) {
result = matches[0];
} else {
result = matches;
}
return result;
});
}
function loadAndWaitForAureliaPage(pageUrl) {
browser.get(pageUrl);
return browser.executeAsyncScript(
'var cb = arguments[arguments.length - 1];' +
'document.addEventListener("aurelia-composed", function (e) {' +
' cb("Aurelia App composed")' +
'}, false);'
).then(function(result){
console.log(result);
return result;
});
}
function waitForRouterComplete() {
return browser.executeAsyncScript(
'var cb = arguments[arguments.length - 1];' +
'document.querySelector("[aurelia-app]")' +
'.aurelia.subscribeOnce("router:navigation:complete", function() {' +
' cb(true)' +
'});'
).then(function(result){
return result;
});
}
/* Plugin hooks */
exports.setup = function(config) {
// Ignore the default Angular synchronization helpers
browser.ignoreSynchronization = true;
// add the aurelia specific valueBind locator
addValueBindLocator();
// attach a new way to browser.get a page and wait for Aurelia to complete loading
browser.loadAndWaitForAureliaPage = loadAndWaitForAureliaPage;
// wait for router navigations to complete
browser.waitForRouterComplete = waitForRouterComplete;
};
exports.teardown = function(config) {};
exports.postResults = function(config) {};
and I added a sample test in my test/e2e/src folder it doesn't get executed. I've also tried implementing a e2e test within the unit test folder since when I run au test I see that a chrome browser opens up.
describe('aurelia homepage', function() {
it('should load page', function() {
browser.get('http://www.aurelia.io');
expect(browser.getTitle()).toEqual('Home | Aurelia');
});
});
But this throws the error browser is undefined. Am I missing something with e2e testing with the cli? I know aurelia-protractor comes pre-installed but I don't see any way to run it.
I know this is a very late answer, but perhaps for others looking for an answer, you could try to import from the aurelia-protractor plugin
import {browser} from 'aurelia-protractor-plugin/protractor';

why I am not able to import lodash in angular2

I am using angular-cli in angular2 rc1 for development.
I have installed lodash node_module through npm and configured it in systemjs using following:
system.config.ts
/***********************************************************************************************
* User Configuration.
**********************************************************************************************/
/** Map relative paths to URLs. */
const map: any = {
};
/** User packages configuration. */
const packages: any = {
};
////////////////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************************
* Everything underneath this line is managed by the CLI.
**********************************************************************************************/
const barrels: string[] = [
// Angular specific barrels.
'#angular/core',
'#angular/common',
'#angular/compiler',
'#angular/http',
'#angular/router',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'ng2-dnd',
'ng2-bootstrap',
'moment',
'lodash',
// Thirdparty barrels.
'rxjs',
// App specific barrels.
'app',
'app/shared',
/** #cli-barrel */
];
const cliSystemConfigPackages: any = {};
barrels.forEach((barrelName: string) => {
if(barrelName=='ng2-dnd'){
cliSystemConfigPackages[barrelName] = { main: 'ng2-dnd' };
}else if (barrelName == 'ng2-bootstrap') {
cliSystemConfigPackages[barrelName] = { main: 'ng2-bootstrap' };
}else if (barrelName == 'lodash') {
cliSystemConfigPackages[barrelName] = { main: 'lodash' };
}else if (barrelName == 'moment') {
cliSystemConfigPackages[barrelName] = { main: 'moment' };
}else{
cliSystemConfigPackages[barrelName] = { main: 'index' };
}
});
/** Type declaration for ambient System. */
declare var System: any;
// Apply the CLI SystemJS configuration.
System.config({
map: {
'#angular': 'vendor/#angular',
'rxjs': 'vendor/rxjs',
'main': 'main.js',
'ng2-dnd': 'vendor/ng2-dnd',
'ng2-bootstrap':'vendor/ng2-bootstrap',
'moment':'vendor/moment',
'lodash':'vendor/lodash'
},
meta: {
lodash: { format: 'amd' }
},
packages: cliSystemConfigPackages
});
// Apply the user's configuration.
System.config({ map, packages });
I would just like to note that other node_modules are working correctly i.e. moment,ng2-bootstrap etc.
angular-cli-build.js
/* global require, module */
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'zone.js/dist/**/*.+(js|js.map)',
'es6-shim/es6-shim.js',
'reflect-metadata/**/*.+(js|js.map)',
'rxjs/**/*.+(js|js.map)',
'#angular/**/*.+(js|js.map)',
'ng2-dnd/**/*.js',
'ng2-bootstrap/**/*.js',
'moment/*.js',
'lodash/*.js'
]
});
};
after this configuration of lodash node_module, I am importing it from the directory dist\vendors\lodash
in my app.component i am importing it as :
import _ from 'lodash';
But I am getting below error:
Cannot find module 'lodash'
any solutions?
thanks in advance
I can suggest you a workaround until they get better support for 3rd party libs. It worked for me :)
In your angular-cli-build.json , make sure it remains like this way
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
...
'lodash/**/*.js'
]
});
};
and in your system-config.ts:
/** Map relative paths to URLs. */
const map: any = {
'lodash': 'vendor/lodash/lodash.js'
};
/** User packages configuration. */
const packages: any = {
'lodash': {
format: 'cjs'
}
};
in your src/index.html add this line
<script src="/vendor/lodash/lodash.js" type="text/javascript"></script>
now in your component where you want to use lodash , write this way
declare var _:any;
#Component({
})
export class YourComponent {
ngOnInit() {
console.log(_.chunk(['a', 'b', 'c', 'd'], 2));
}
}
Try using:
import * as _ from 'lodash';

Create config variables in sails.js?

I'm converting an app of mine from Express to sails.js - is there a way I can do something like this in Sails?
From my app.js file in Express:
var globals = {
name: 'projectName',
author: 'authorName'
};
app.get('/', function (req, res) {
globals.page_title = 'Home';
res.render('index', globals);
});
This let me access those variables on every view without having to hardcode them into the template. Not sure how/where to do it in Sails though.
You can create your own config file in config/ folder. For example config/myconf.js with your config variables:
module.exports.myconf = {
name: 'projectName',
author: 'authorName',
anyobject: {
bar: "foo"
}
};
and then access these variables from any view via global sails variable.
In a view:
<!-- views/foo/bar.ejs -->
<%= sails.config.myconf.name %>
<%= sails.config.myconf.author %>
In a service
// api/services/FooService.js
module.exports = {
/**
* Some function that does stuff.
*
* #param {[type]} options [description]
* #param {Function} cb [description]
*/
lookupDumbledore: function(options, cb) {
// `sails` object is available here:
var conf = sails.config;
cb(null, conf.whatever);
}
};
// `sails` is not available out here
// (it doesn't exist yet)
console.log(sails); // ==> undefined
In a model:
// api/models/Foo.js
module.exports = {
attributes: {
// ...
},
someModelMethod: function (options, cb) {
// `sails` object is available here:
var conf = sails.config;
cb(null, conf.whatever);
}
};
// `sails is not available out here
// (doesn't exist yet)
In a controller:
Note: This works the same way in policies.
// api/controllers/FooController.js
module.exports = {
index: function (req, res) {
// `sails` is available in here
return res.json({
name: sails.config.myconf.name
});
}
};
// `sails is not available out here
// (doesn't exist yet)
I just made a service which delivers a value:
maxLimbs: function(){
var maxLimbs = 15;
return maxLimbs;
}

Resources