diff --git a/README.md b/README.md index 0421337..9e6e990 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,14 @@ module.exports = binding An added benefit of this approach is that your native modules will work across multiple node and electron versions without having the user need to reinstall or recompile them - as long as you produce prebuilds for all versions. With Node-API you only have to produce prebuilds for every runtime. -When publishing your module to npm remember to include the `./prebuilds` folder. + +## Platform-specific Packages +As an alternate to including all prebuilds directly in your published package, you can use `--platform-packages` to setup the prebuilds for publishing as separate platform-specific packages. Using this option, each prebuild directory will also include a package.json that specifies the target platform and architectures along with some basic package files. Each of these prebuild directories can then be published as separate packages in NPM. In addition, +the main package should specify all the platform packages as `optionalDependencies`. When installed, npm (or similar) will then only install the optional dependency with the platform & architecture matching the target machine. + +This provides both the efficiency of only needing to install the binaries needed for the current platform, and the key benefit of the `prebuildify` approach in that binaries are downloaded as part of the normal npm install process (without install scripts). When using this option, you should omit the `./prebuilds` folder when publishing your main package, since they will be separately downloaded by npm. In npm 7+, only the matching platform package will be downloaded (and installed). In yarn and older versions of npm, all the platform packages will be downloaded (once to the package cache), but only the matching platform package will be installed. + +If you do not use this option, when publishing your package to npm, remember to include the `./prebuilds` folder. That's it! Happy native hacking. @@ -94,6 +101,7 @@ Options can be provided via (in order of precedence) the programmatic API, the C | `--tag-uv` | - | `false` | Tag prebuild with `uv`\*\*\* | `--tag-armv` | - | `false` | Tag prebuild with `armv`\*\*\* | `--tag-libc` | - | `false` | Tag prebuild with `libc`\*\*\* +| `--platform-packages`| - | `false` | Add package.json and basic files for package publishing | `--preinstall` | - | - | Command to run before build | `--postinstall` | - | - | Command to run after build | `--shell` | `PREBUILD_SHELL` | `'sh'` on Android | Shell to spawn commands in diff --git a/bin.js b/bin.js index aacbef7..f920106 100755 --- a/bin.js +++ b/bin.js @@ -15,9 +15,10 @@ var argv = minimist(process.argv.slice(2), { tagArmv: 'tag-armv', tagLibc: 'tag-libc', electronCompat: 'electron-compat', + platformPackages: 'platform-packages', cache: 'c' }, - boolean: ['quiet', 'strip', 'napi', 'debug', 'all', 'electron-compat'] + boolean: ['quiet', 'platform-packages', 'strip', 'napi', 'debug', 'all', 'electron-compat'] }) argv.targets = [].concat(argv.target || []) diff --git a/index.js b/index.js index b139844..de3b689 100644 --- a/index.js +++ b/index.js @@ -62,6 +62,13 @@ function prebuildify (opts, cb) { if (opts.arch === 'ia32' && opts.platform === 'linux' && opts.arch !== os.arch()) { opts.env.CFLAGS = '-m32' } + var packageData + if (opts.platformPackages) { + if (opts.arch.indexOf('+') > -1) { + throw new Error('Platform packages do not support multi-arch values') + } + packageData = JSON.parse(fs.readFileSync(path.join(opts.cwd, 'package.json'))) + } // Since npm@5.6.0 npm adds its bundled node-gyp to PATH, taking precedence // over the local .bin folder. Counter that by (again) adding .bin to PATH. @@ -71,7 +78,26 @@ function prebuildify (opts, cb) { if (err) return cb(err) loop(opts, function (err) { if (err) return cb(err) - + if (opts.platformPackages) { + var packageName = packageData.name + var description = 'Platform specific binary for ' + packageName + ' on ' + opts.platform + ' OS with ' + opts.arch + ' architecture' + fs.writeFileSync(path.join(opts.builds, 'package.json'), JSON.stringify({ + // append platform, and prefix with scoped name matching package name if unscoped + name: (packageName[0] === '@' ? '' : '@' + packageName + '/') + packageName + '-' + opts.platform + '-' + opts.arch, + version: packageData.version, + os: [opts.platform], + cpu: [opts.arch], + // copy some of the useful package metadata, if any of these are missing, should just be skipped when stringified + license: packageData.license, + author: packageData.author, + repository: packageData.repository, + bugs: packageData.bugs, + homepage: packageData.homepage, + description + }, null, 2)) + fs.writeFileSync(path.join(opts.builds, 'index.js'), '') // needed to resolve package + fs.writeFileSync(path.join(opts.builds, 'README.md'), description) + } if (opts.artifacts) return copyRecursive(opts.artifacts, opts.builds, cb) return cb() }) diff --git a/package.json b/package.json index 47110c6..cb20fb5 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { - "name": "prebuildify", - "version": "5.0.0", + "name": "prebuildify-platform-packages", + "version": "5.0.1", "description": "Create and package prebuilds for native modules", "main": "index.js", "dependencies": { "execspawn": "^1.0.1", "mkdirp-classic": "^0.5.3", - "node-abi": "^3.3.0", + "node-abi": "^3.28.0", "npm-run-path": "^3.1.0", "minimist": "^1.2.5", "pump": "^3.0.0", @@ -18,7 +18,7 @@ "tape": "^4.6.3" }, "bin": { - "prebuildify": "./bin.js" + "prebuildify-platform-packages": "./bin.js" }, "files": [ "bin.js",