diff --git a/README.md b/README.md index 2ae6b29cce06..4ac256847b57 100644 --- a/README.md +++ b/README.md @@ -15,36 +15,71 @@ editor](https://github.com/atom/atom) and many other [apps](https://electron.ato Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important announcements. -This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). +This project adheres to the Contributor Covenant +[code of conduct](https://github.com/electron/electron/tree/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable -behavior to electron@github.com. +behavior to [electron@github.com](mailto:electron@github.com). -## Downloads +## Installation -To install prebuilt Electron binaries, use -[`npm`](https://docs.npmjs.com/): +To install prebuilt Electron binaries, use [`npm`](https://docs.npmjs.com/). +The preferred method is to install Electron as a development dependency in your +app: ```sh -# Install as a development dependency -npm install electron --save-dev - -# Install the `electron` command globally in your $PATH -npm install electron -g +npm install electron --save-dev --save-exact ``` -See the [releases page](https://github.com/electron/electron/releases) for -prebuilt binaries, debug symbols, and more. +The `--save-exact` flag is recommended as Electron does not follow semantic +versioning. For info on how to manage Electron versions in your apps, see +[Electron versioning](https://electron.atom.io/docs/tutorial/electron-versioning/). + +For more installation options and troubleshooting tips, see +[installation](https://electron.atom.io/docs/tutorial/installation/). + +## Quick Start + +Clone and run the +[electron/electron-quick-start](https://github.com/electron/electron-quick-start) +repository to see a minimal Electron app in action: + +``` +git clone https://github.com/electron/electron-quick-start +cd electron-quick-start +npm install +npm start +``` + +## Resources for Learning Electron + +- [electron.atom.io/docs](http://electron.atom.io/docs) - all of Electron's documentation +- [electron/electron-quick-start](https://github.com/electron/electron-quick-start) - a very basic starter Electron app +- [electron.atom.io/community/#boilerplates](http://electron.atom.io/community/#boilerplates) - sample starter apps created by the community +- [electron/simple-samples](https://github.com/electron/simple-samples) - small applications with ideas for taking them further +- [electron/electron-api-demos](https://github.com/electron/electron-api-demos) - an Electron app that teaches you how to use Electron +- [hokein/electron-sample-apps](https://github.com/hokein/electron-sample-apps) - small demo apps for the various Electron APIs + +## Programmatic usage + +Most people use Electron from the command line, but if you require `electron` inside +your **Node app** (not your Electron app) it will return the file path to the +binary. Use this to spawn Electron from Node scripts: + +```javascript +const electron = require('electron') +const proc = require('child_process') + +// will print something similar to /Users/maf/.../Electron +console.log(electron) + +// spawn Electron +const child = proc.spawn(electron) +``` ### Mirrors - [China](https://npm.taobao.org/mirrors/electron) -## Documentation - -Guides and the API reference are located in the -[docs](https://github.com/electron/electron/tree/master/docs) directory. It also -contains documents describing how to build and contribute to Electron. - ## Documentation Translations - [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR) @@ -60,11 +95,6 @@ contains documents describing how to build and contribute to Electron. - [French](https://github.com/electron/electron/tree/master/docs-translations/fr-FR) - [Indonesian](https://github.com/electron/electron/tree/master/docs-translations/id) -## Quick Start - -Clone and run the [`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) -repository to see a minimal Electron app in action. - ## Community You can ask questions and interact with the community in the following diff --git a/docs/tutorial/installation.md b/docs/tutorial/installation.md new file mode 100644 index 000000000000..ca2e92a2071f --- /dev/null +++ b/docs/tutorial/installation.md @@ -0,0 +1,56 @@ +# Installation + +> Tips for installing Electron + +To install prebuilt Electron binaries, use [`npm`](https://docs.npmjs.com/). +The preferred method is to install Electron as a development dependency in your +app: + +```sh +npm install electron --save-dev --save-exact +``` + +The `--save-exact` flag is recommended as Electron does not follow semantic +versioning. See the +[versioning doc](https://electron.atom.io/docs/tutorial/electron-versioning/) +for info on how to manage Electron versions in your apps. + +## Global Installation + +You can also install the `electron` command globally in your `$PATH`: + +```sh +npm install electron -g +``` + +## Customization + +If you want to change the architecture that is downloaded (e.g., `ia32` on an +`x64` machine), you can use the `--arch` flag with npm install or set the +`npm_config_arch` environment variable: + +```shell +npm install --arch=ia32 electron +``` + +## Proxies + +If you need to use an HTTP proxy you can [set these environment variables](https://github.com/request/request/tree/f0c4ec061141051988d1216c24936ad2e7d5c45d#controlling-proxy-behaviour-using-environment-variables). + +## Troubleshooting + +When running `npm install electron`, some users occasionally encounter +installation errors. + +In almost all cases, these errors are the result of network problems and not +actual issues with the `electron` npm package. Errors like `ELIFECYCLE`, +`EAI_AGAIN`, `ECONNRESET`, and `ETIMEDOUT` are all indications of such +network problems. The best resolution is to try switching networks, or +just wait a bit and try installing again. + +You can also attempt to download Electron directly from +[electron/electron/releases](https://github.com/electron/electron/releases) +if installing via `npm` is failing. + +If you need to force a re-download of the asset and the SHASUM file set the +`force_no_cache` enviroment variable to `true`. \ No newline at end of file diff --git a/npm/cli.js b/npm/cli.js new file mode 100755 index 000000000000..bfe2c11be311 --- /dev/null +++ b/npm/cli.js @@ -0,0 +1,10 @@ +#!/usr/bin/env node + +var electron = require('./') + +var proc = require('child_process') + +var child = proc.spawn(electron, process.argv.slice(2), {stdio: 'inherit'}) +child.on('close', function (code) { + process.exit(code) +}) diff --git a/npm/index.js b/npm/index.js new file mode 100644 index 000000000000..eb480b9e01dd --- /dev/null +++ b/npm/index.js @@ -0,0 +1,10 @@ +var fs = require('fs') +var path = require('path') + +var pathFile = path.join(__dirname, 'path.txt') + +if (fs.existsSync(pathFile)) { + module.exports = path.join(__dirname, fs.readFileSync(pathFile, 'utf-8')) +} else { + throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again') +} diff --git a/npm/install.js b/npm/install.js new file mode 100755 index 000000000000..3a93295f35db --- /dev/null +++ b/npm/install.js @@ -0,0 +1,65 @@ +#!/usr/bin/env node + +// maintainer note - x.y.z-ab version in package.json -> x.y.z +var version = require('./package').version.replace(/-.*/, '') + +var fs = require('fs') +var os = require('os') +var path = require('path') +var extract = require('extract-zip') +var download = require('electron-download') + +var installedVersion = null +try { + installedVersion = fs.readFileSync(path.join(__dirname, 'dist', 'version'), 'utf-8').replace(/^v/, '') +} catch (ignored) { + // do nothing +} + +var platformPath = getPlatformPath() + +if (installedVersion === version && fs.existsSync(path.join(__dirname, platformPath))) { + process.exit(0) +} + +// downloads if not cached +download({ + cache: process.env.electron_config_cache, + version: version, + platform: process.env.npm_config_platform, + arch: process.env.npm_config_arch, + strictSSL: process.env.npm_config_strict_ssl === 'true', + force: process.env.force_no_cache === 'true', + quiet: ['info', 'verbose', 'silly', 'http'].indexOf(process.env.npm_config_loglevel) === -1 +}, extractFile) + +// unzips and makes path.txt point at the correct executable +function extractFile (err, zipPath) { + if (err) return onerror(err) + extract(zipPath, {dir: path.join(__dirname, 'dist')}, function (err) { + if (err) return onerror(err) + fs.writeFile(path.join(__dirname, 'path.txt'), platformPath, function (err) { + if (err) return onerror(err) + }) + }) +} + +function onerror (err) { + throw err +} + +function getPlatformPath () { + var platform = process.env.npm_config_platform || os.platform() + + switch (platform) { + case 'darwin': + return 'dist/Electron.app/Contents/MacOS/Electron' + case 'freebsd': + case 'linux': + return 'dist/electron' + case 'win32': + return 'dist/electron.exe' + default: + throw new Error('Electron builds are not available on platform: ' + platform) + } +} diff --git a/npm/package.json b/npm/package.json new file mode 100644 index 000000000000..87935105dca7 --- /dev/null +++ b/npm/package.json @@ -0,0 +1,26 @@ +{ + "scripts": { + "cache-clean": "rm -rf ~/.electron && rm -rf dist", + "postinstall": "node install.js", + "pretest": "npm run cache-clean", + "test": "standard" + }, + "bin": { + "electron": "cli.js" + }, + "main": "index.js", + "types": "electron.d.ts", + "dependencies": { + "@types/node": "^7.0.18", + "electron-download": "^3.0.1", + "extract-zip": "^1.0.3" + }, + "devDependencies": { + "home-path": "^0.1.1", + "path-exists": "^2.0.0", + "standard": "^5.4.1" + }, + "directories": { + "test": "test" + } +} diff --git a/package.json b/package.json index f7ecebed82b5..f0fd42c54859 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,22 @@ { "name": "electron", "version": "1.7.5", + "repository": "https://github.com/electron/electron", + "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { "asar": "^0.11.0", "browserify": "^13.1.0", "check-for-leaks": "^1.0.2", + "dotenv-safe": "^4.0.4", "electabul": "~0.0.4", "electron-docs-linter": "^2.3.3", "electron-typescript-definitions": "^1.2.7", + "github": "^9.2.0", "husky": "^0.14.3", "request": "^2.68.0", "standard": "^8.4.0", - "standard-markdown": "^4.0.0" + "standard-markdown": "^4.0.0", + "temp": "^0.8.3" }, "standard": { "ignore": [ @@ -43,11 +48,17 @@ "create-api-json": "electron-docs-linter docs --outfile=out/electron-api.json --version=$npm_package_version", "create-typescript-definitions": "npm run create-api-json && electron-typescript-definitions --in=out/electron-api.json --out=out/electron.d.ts", "preinstall": "node -e 'process.exit(0)'", + "publish-to-npm": "node ./script/publish-to-npm.js", "prepack": "check-for-leaks", "prepush": "check-for-leaks", "release": "./script/upload.py -p", "repl": "python ./script/start.py --interactive", "start": "python ./script/start.py", "test": "python ./script/test.py" - } + }, + "license": "MIT", + "author": "Electron Community", + "keywords": [ + "electron" + ] } diff --git a/script/publish-to-npm.js b/script/publish-to-npm.js new file mode 100644 index 000000000000..21960455cfe9 --- /dev/null +++ b/script/publish-to-npm.js @@ -0,0 +1,125 @@ +const temp = require('temp') +const fs = require('fs') +const path = require('path') +const childProcess = require('child_process') +const GitHubApi = require('github') +const request = require('request') +const assert = require('assert') +const rootPackageJson = require('../package.json') + +const github = new GitHubApi({ + // debug: true, + headers: { 'User-Agent': 'electron-npm-publisher' }, + followRedirects: false +}) + +let tempDir +temp.track() // track and cleanup files at exit + +const files = [ + 'cli.js', + 'index.js', + 'install.js', + 'package.json', + 'README.md' +] + +const jsonFields = [ + 'name', + 'version', + 'repository', + 'description', + 'license', + 'author', + 'keywords' +] + +let npmTag = '' + +new Promise((resolve, reject) => { + temp.mkdir('electron-npm', (err, dirPath) => { + if (err) { + reject(err) + } else { + resolve(dirPath) + } + }) +}) +.then((dirPath) => { + tempDir = dirPath + // copy files from `/npm` to temp directory + files.forEach((name) => { + fs.writeFileSync( + path.join(tempDir, name), + fs.readFileSync(path.join(__dirname, '..', name === 'README.md' ? '' : 'npm', name)) + ) + }) + // copy from root package.json to temp/package.json + const packageJson = require(path.join(tempDir, 'package.json')) + jsonFields.forEach((fieldName) => { + packageJson[fieldName] = rootPackageJson[fieldName] + }) + fs.writeFileSync( + path.join(tempDir, 'package.json'), + JSON.stringify(packageJson, null, 2) + ) + + return github.repos.getReleases({ + owner: 'electron', + repo: 'electron' + }) +}) +.then((releases) => { + // download electron.d.ts from release + const release = releases.data.find( + (release) => release.tag_name === `v${rootPackageJson.version}` + ) + if (!release) { + throw new Error(`cannot find release with tag v${rootPackageJson.version}`) + } + return release +}) +.then((release) => { + const tsdAsset = release.assets.find((asset) => asset.name === 'electron.d.ts') + if (!tsdAsset) { + throw new Error(`cannot find electron.d.ts from v${rootPackageJson.version} release assets`) + } + return new Promise((resolve, reject) => { + request.get({ + url: tsdAsset.url, + headers: { + 'accept': 'application/octet-stream', + 'user-agent': 'electron-npm-publisher' + } + }, (err, response, body) => { + if (err || response.statusCode !== 200) { + reject(err || new Error('Cannot download electron.d.ts')) + } else { + fs.writeFileSync(path.join(tempDir, 'electron.d.ts'), body) + resolve(release) + } + }) + }) +}) +.then((release) => { + npmTag = release.prerelease ? 'beta' : 'latest' +}) +.then(() => childProcess.execSync('npm pack', { cwd: tempDir })) +.then(() => { + // test that the package can install electron prebuilt from github release + const tarballPath = path.join(tempDir, `${rootPackageJson.name}-${rootPackageJson.version}.tgz`) + return new Promise((resolve, reject) => { + childProcess.execSync(`npm install ${tarballPath} --force --silent`, { + env: Object.assign({}, process.env, { electron_config_cache: tempDir }), + cwd: tempDir + }) + const checkVersion = childProcess.execSync(`${path.join(tempDir, 'node_modules', '.bin', 'electron')} -v`) + assert.strictEqual(checkVersion.toString().trim(), `v${rootPackageJson.version}`) + resolve(tarballPath) + }) +}) +.then((tarballPath) => childProcess.execSync(`npm publish ${tarballPath} --tag ${npmTag}`)) +.catch((err) => { + console.error(`Error: ${err}`) + process.exit(1) +}) diff --git a/script/upload.py b/script/upload.py index e3762b80395d..455ed789e0a0 100755 --- a/script/upload.py +++ b/script/upload.py @@ -72,6 +72,8 @@ def main(): # Press the publish button. publish_release(github, release['id']) + # TODO: run publish-to-npm script here + # Do not upload other files when passed "-p". return