Background
I am very new to Node.js so please don't hate..
I found NPM very useful because I can install Node.js packages globally and then use them like standalone, available-on-path apps.
This does work on Windows, which really suprises me.
For instance I installed UglifyJS this way, via npm install -g uglifyjs and now I can run it from anywhere in my system, from the console via uglifyjs <rest of command> (not node uglifyjs .. or sth else).
I'd like to create my own stand-alone Node.js application. How do I get starded? I am asking here because most tutorials only cover how to write a simple script and then run it va node (which I already covered)
My current config
package.json:
{
"name": "hash",
"version": "1.0.0",
"author": "Kiel V.",
"engines": [
"node >= 0.8.0"
],
"main": "hash.js",
"dependencies": {
"commander" : "1.2.0"
},
"scripts": {
"start": "node hash.js"
}
}
hash.js:
var crypto = require('crypto'),
commander = require('commander');
/* For use as a library */
function hash(algorithm, str) {
return crypto.createHash(algorithm).update(str).digest('hex');
}
exports.hash = hash;
/* For use as a stand-alone app */
commander
.version('1.0.0')
.usage('[options] <plain ...>')
.option('-a, --algorithm [algorithm]', 'Hash algorithm', 'md5')
.parse(process.argv);
commander.args.forEach(function(plain){
console.log( plain + ' -> ' + hash(commander.algorithm, plain) );
});
Question:
Suppose I have only these two files in node-hash directory. How do I install this project, so that later I can run it in cmd.exe via hash -a md5 plaintext just like coffescript, jslint etc. installs ?
You have to add some code into package.json and hash.js, then you can run this command to install the package from local folder.
npm install -g ./node-hash
package.json
{
"name": "hash",
"version": "1.0.0",
"author": "Kiel V.",
"engines": [
"node >= 0.8.0"
],
"bin": {
"hash": "hash.js"
},
"main": "hash.js",
"dependencies": {
"commander" : "1.2.0"
},
"scripts": {
"start": "node hash.js"
}
}
hash.js
#!/usr/bin/env node
var crypto = require('crypto'),
commander = require('commander');
/* For use as a library */
function hash(algorithm, str) {
return crypto.createHash(algorithm).update(str).digest('hex');
}
exports.hash = hash;
/* For use as a stand-alone app */
commander
.version('1.0.0')
.usage('[options] <plain ...>')
.option('-a, --algorithm [algorithm]', 'Hash algorithm', 'md5')
.parse(process.argv);
commander.args.forEach(function(plain){
console.log( plain + ' -> ' + hash(commander.algorithm, plain) );
});
Related
So i have this very simple electron.js test-project which works fine with npm start:
const { app, nativeImage } = require('electron');
const electron = require('electron');
const path = require('path');
const Tray = electron.Tray
const iconpath = path.join(__dirname, './logo_transparent_white_512x512.png')
app.on('ready', function(){
icon = nativeImage.createFromPath(iconpath);
icon = icon.resize({ width: 16, height: 16})
new Tray(icon);
console.log('ready');
})
The package.json looks like this:
{
"name": "electronbuilder",
"version": "1.0.2",
"description": "dadlu",
"main": "main.js",
"homepage": "www.test.com",
"dependencies": {
"path": "^0.12.7"
},
"devDependencies": {
"electron": "^11.1.1",
"electron-builder": "^22.9.1"
},
"scripts": {
"start": "electron .",
"dist": "electron-builder"
},
"author": "test-author",
"license": "ISC",
"build": {
"appId": "com.elecctron.builder",
"productName": "testBuild",
"linux": {
"target": [
"deb"
],
"maintainer": "test-maintainer",
},
"deb": {
"depends": [
"libappindicator1",
"libnotify4"
]
},
"extraFiles": [
"./logo_transparent_white_512x512.png"
]
}
}
After running:
yarn dist
and waiting a minute, I can install the package. But running it doesn't do anything.
when enabling the console ('add to desktop', 'open with Text Editor', 'Terminal=true') I can observe, that the app started successfully:
console.log('ready') got executed
I tried all sorts of ways to get the tray icon to work, stubbing across the weirdest things. F.e. when building the Icon like this:
tray = new Tray(./logo_transparent_white_512x512.png);
it does work with npm start, but after yarn dist, nothing happends. Though, going into the applications folder and running
$ ./{name}
it starts up fine, including the tray icon. (./logo_transparent_white_512x512.png isn't 512x512, i already resized it to 256x256)
its cant be an lib problem either, because this project can be build fine on my system.
I hope someone can help me, ive got my first real project ready, but can only start it with npm start. Any attempts to build it fail, meaning the tray icon doesn't show up.
If some information is missing, feel free to ask.
Is it possible to use the Electron built in auto updater with Gitlab tags?
I have seen that you can use Electron with GitHub releases, via electron-builder, but I am not sure the same can be said with Gitlab, as the use of Github tokens is required.
If there is no option to use Gitlab, are the only other options (a) a self hosted squirrel server, or (b) github releases?
You can use a generic host which is the easiest method, see:
https://gist.github.com/iffy/0ff845e8e3f59dbe7eaf2bf24443f104
You can edit updates.json/yml to point to the gitlab release, and it will be no worse than a generic server. It won't check the gitlab credentials, though.
You can use Amazon S3 or Bintray, see:
https://github.com/electron-userland/electron-builder/wiki/Publishing-Artifacts
Google Compute claims that they can be setup to be compatible with S3, so you could probably use them as well.
You may be able to use Gitlab releases the same as Github using the git+ssh syntax. Haven't tested that, but see Install npm module from gitlab private repository
My working example
.gitlab-ci
variables:
VERSION_ID: '1.0.$CI_PIPELINE_ID'
stages:
- build
build:
image: slauta93/electron-builder-win
stage: build
artifacts:
paths:
- $CI_PROJECT_DIR/dist/*.*
script:
- sed "s/0.0.0/${VERSION_ID}/g" package.json > _package.json && mv _package.json package.json
- npm install && npm run build
main.js
// Inital app
const electron = require("electron");
const updater = require("electron-updater");
const autoUpdater = updater.autoUpdater;
...
///////////////////
// Auto upadater //
///////////////////
autoUpdater.requestHeaders = { "PRIVATE-TOKEN": "Personal access Token" };
autoUpdater.autoDownload = true;
autoUpdater.setFeedURL({
provider: "generic",
url: "https://gitlab.com/_example_repo_/-/jobs/artifacts/master/raw/dist?job=build"
});
autoUpdater.on('checking-for-update', function () {
sendStatusToWindow('Checking for update...');
});
autoUpdater.on('update-available', function (info) {
sendStatusToWindow('Update available.');
});
autoUpdater.on('update-not-available', function (info) {
sendStatusToWindow('Update not available.');
});
autoUpdater.on('error', function (err) {
sendStatusToWindow('Error in auto-updater.');
});
autoUpdater.on('download-progress', function (progressObj) {
let log_message = "Download speed: " + progressObj.bytesPerSecond;
log_message = log_message + ' - Downloaded ' + parseInt(progressObj.percent) + '%';
log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')';
sendStatusToWindow(log_message);
});
autoUpdater.on('update-downloaded', function (info) {
sendStatusToWindow('Update downloaded; will install in 1 seconds');
});
autoUpdater.on('update-downloaded', function (info) {
setTimeout(function () {
autoUpdater.quitAndInstall();
}, 1000);
});
autoUpdater.checkForUpdates();
function sendStatusToWindow(message) {
console.log(message);
}
...
package.json
{
"name": "electron-updater-gitlab",
"version": "0.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"pack": "node_modules/.bin/electron-builder --dir",
"build": "node_modules/.bin/electron-builder --win",
"postinstall": "",
"install": "node-gyp install",
},
"build": {
"appId": "com.electron.app",
"publish": [
{
"provider": "generic",
"url": "https://gitlab.com"
}
],
"win": {
"target": [
"nsis"
],
"verifyUpdateCodeSignature": false
},
"mac": {
"category": "public.app-category.productivity",
"identity": "Mac Developer: username (XXXXXXXX)",
"target": [
"dmg"
]
},
"linux": {
"target": [
"AppImage"
]
}
},
"dependencies": {
"electron-updater": "^2.7.2"
},
"devDependencies": {
"electron": "1.6.11",
"electron-builder": "^19.16.2"
}
}
After considering the answers in this issue and others, I ended up using GitLab Pages to publish my build artifacts. This allowed me to make make the installer files freely available to everyone in my organization without opening up the repo to everyone.
.gitlab-ci.yml:
stages:
- test
- build
- deploy
test-app:
stage: test
image: node:lts-alpine
script:
- npm install
- npm run test:colors
electron-release-build:
only:
- master
stage: build
image: electronuserland/builder:wine
script:
- npm ci
- npm run package:publish
artifacts:
paths:
- electron-release/*.exe*
- electron-release/*.yml
expire_in: 1 month
pages:
stage: deploy
only:
- master
image: alpine:latest
dependencies:
- electron-release-build
script:
# Note that `public` already exists in this repo, and has an index.html to
# to act as a downloads page.
- cp electron-release/*.exe electron-release/*.blockmap electron-release/*.yml public
- EXE_FILENAME=$(find ./electron-release -maxdepth 1 -name "Maestro*.exe")
- EXE_BASENAME=$(basename "$EXE_FILENAME")
- sed -i "s/INSERT_FILE_NAME/${EXE_BASENAME}/g" ./public/index.html
artifacts:
paths:
- public
Relevant part of package.json:
{
"build": {
"asar": true,
"appId": "com.myapp.app",
"productName": "myapp",
"directories": {
"output": "electron-release"
},
"extraFiles": [
"build/icon.ico"
],
"detectUpdateChannel": false,
"publish": {
"provider": "generic",
"url": "https://myappgroup.pages.example.com/myapp"
},
"win": {
"target": "nsis",
"verifyUpdateCodeSignature": false,
"icon": "build/icon.ico"
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowElevation": true,
"allowToChangeInstallationDirectory": true
}
}
}
No changes were needed anywhere else.
This also simplified things a bit, since I don't think I could use the provider URL proposed in another answer due to permissions (https://gitlab.com/_example_repo_/-/jobs/artifacts/master/raw/dist?job=build 404s for me).
I am using Gulp to start a web application. I have the following basic code for my gulpfile.js:
var gulp = require('gulp'),
nodemon = require('gulp-nodemon');
gulp.task('default', function () {
nodemon({
script: 'server.js'
, ext: 'js html'
, env: { 'NODE_ENV': 'development' }
})
})
Using Gulp, I want to check for dependencies and if they are not available then install them and then run 'script.js'. How can this be done?
I have the following package.json:
{
"name": "sample-project",
"version": "1.0.0",
"description": "Displays users and user details",
"main": "server.js",
"dependencies": {
"jquery" : “>=1.5.1",
“bootstrap”: ">= 3.0.0”
}
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "Arihant Jain",
"license": "ISC"
}
You can run npm install independently from an executing task using node's child_process as such:
var gulp = require('gulp');
var nodemon = require('gulp-nodemon');
var child_process = require('child_process');
gulp.task('default', function () {
// Run npm install from the child process
child_process.exe('npm install', function(err, stdout, stderr){
// if everything goes well
if(!err){
// run nodemon
nodemon({
script: 'server.js'
, ext: 'js html'
, env: { 'NODE_ENV': 'development' }
})
}
});
})
Given your requirement:
Using Gulp, I want to check for dependencies and if they are not
available then install them...
That is exactly what npm install does. It checks the local package.json and proceeds to install missing packages.
So, I worked it around in a way by using gulp-run. I actually run the command npm install.
gulpfile looks like this:
var gulp = require('gulp'),
nodemon = require('gulp-nodemon')
run = require('gulp-run')
runSequence = require('run-sequence')
open = require('gulp-open');
gulp.task('default', function() {
runSequence('dependencies',
'start',
'uri');
});
gulp.task('dependencies', function() {
return run('npm install').exec();
})
gulp.task('uri', function(){
gulp.src(__filename)
.pipe(open({uri: 'http://localhost:3000/index.html'}));
});
gulp.task('start', function () {
nodemon({
script: 'server.js'
, ext: 'js html'
, env: { 'NODE_ENV': 'development' }
})
})
I am developing Android app using cordova, and I want to add some javascript library in my project. For example, if I want to add async.js, Openlayers and some other library in my cordova app and I don't want to add them manually, how should I resolve this?
We're doing a Cordova app where I work right now.
We primarily use npm to download any dependencies (like lodash, for example, or any other dependencies available via npm). Then we use webpack to bundle all of the dependencies, and then reference the bundle in www/index.html:
<script src="bundle.js"></script>
I'm using npm+bower+gruntto manage the depencies, and it works.
In npm, you will define the packages you need including the cordova plugins in package.json:
{
"name": "i18n",
"version": "1.3.0",
"private": true,
"dependencies": {},
"devDependencies": {
"cordova": "~5.3.3",
"grunt": "~0.4.5",
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "grunt test"
},
"cordovaPlatforms": [
"ios",
"android"
],
"cordovaPlugins": [
"org.apache.cordova.device",
"cordova-plugin-compat",
"cordova-plugin-console",
"cordova-plugin-geolocation"
]
}
Then you will manage your dependencies in bower.json, for example:
{
"name": "i18n",
"version": "1.3.0",
"dependencies": {
"ngCordova": "~0.1.18",
"ng-cordova-oauth": "~0.1.4"
},
"devDependencies": {
"ngCordova": "~0.1.15-alpha"
}
}
How you build the project is through grunt build, and you want to build the src into www or asset/www. And you can cordova run <platform> or grunt serve to run the app.
TLDR and simple
Use the npm package: cordova-import-npm
Long question and DIY
Because I wanted to avoid bundlers such as webpack or grunt, I used an Apache Cordova Hook
Just add this to your config.xml
<hook src="hooks/importNpmPackages.js" type="before_prepare"/>
And create this file hooks/importNpmPackages.js
const fse = require('fs-extra')
const path = require('path')
const twoSpaces = ' ' // for log indentation
var projectRoot
module.exports = function (context) {
console.log(`${context.hook} : ${path.relative(context.opts.projectRoot, context.scriptLocation)}`)
projectRoot = context.opts.projectRoot
console.log(twoSpaces + 'Project root directory: ' + projectRoot)
copyFile('jquery', path.join('dist', 'jquery.min.js'), path.join('www', 'js', 'res', 'jquery.min.js'))
copyFile('bootstrap', path.join('dist', 'js', 'bootstrap.min.js'), path.join('www', 'js', 'res', 'bootstrap.min.js'))
copyFile('bootstrap', path.join('dist', 'css', 'bootstrap.min.css'), path.join('www', 'css', 'res', 'bootstrap.min.css'))
}
function copyFile (npmPackage, // oficial name of the npm package from which the file is to be copied from
fileRelativePath, // file path with respect to the main directory of the npm package (node_modules/<package>/)
destFilePath) { // file's path to where it is copied, relative to the project bin/ directory
// trick to get the npm module main directory
// https://stackoverflow.com/a/49455609/1243247
const packageDirFullpath = path.dirname(require.resolve(path.join(npmPackage, 'package.json')))
const fileOriginFullPath = path.join(packageDirFullpath, fileRelativePath)
const fileDestFullPath = path.join(projectRoot, destFilePath)
fse.copySync(fileOriginFullPath, fileDestFullPath)
const consoleMsg = npmPackage + ': ' +
path.relative(projectRoot, fileOriginFullPath) + ' -> ' +
path.relative(projectRoot, fileDestFullPath)
console.log(twoSpaces + consoleMsg)
}
It simply copies the desired dependencies files to the www folder where you decide. In this exemple I copy jquery and bootstrap.
I have a Node app I'd like to test, and get coverage report. I followed the Getting Started Guide but it doesn't seem to work.
My source, in src/two.js:
var two = 1 + 1;
module.exports = two;
My test, in test/two.js:
var expect = require('expect');
var two = require('../src/two');
describe('two', function() {
it('should be 2', function(done) {
expect(two).toBe(2);
done();
});
});
And my package.json:
{
"scripts": {
"test": "mocha",
"cover": "mocha -r blanket -R html-cov > coverage.html"
},
"devDependencies": {
"blanket": "^1.2.1",
"expect": "^1.13.4",
"mocha": "^2.3.4"
}
}
When I run npm run test everything works as you'd expect. But when I run npm run cover, in my coverage.html file I get 0% coverage 0 SLOC and nothing else.
I got it to run by adding this to package.json:
...
"config": {
"blanket": {
"pattern": "src",
"data-cover-never": ["node_modules"]
}
},
...
Apparently Blanket does not default to src despite what the guide says (there's an old open issue on GitHub).
It also tries to cover all of the paths that match the pattern, not just the src dir, so in this case it tried to cover external files as well (node_modules/has/src/index.js, which was installed by Expect). I had to add the data-cover-never to avoid it.