diff --git a/default.nix b/default.nix index a10eaa3..08f947e 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ {pkgs ? import { inherit system; - }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-12_x"}: + }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-14_x"}: let nodeEnv = import ./node-env.nix { diff --git a/node-env.nix b/node-env.nix index 2590dd2..5dad9ec 100644 --- a/node-env.nix +++ b/node-env.nix @@ -165,7 +165,11 @@ let if(process.argv[2] == "development") { replaceDependencies(packageObj.devDependencies); } + else { + packageObj.devDependencies = {}; + } replaceDependencies(packageObj.optionalDependencies); + replaceDependencies(packageObj.peerDependencies); /* Write the fixed package.json file */ fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2)); @@ -270,7 +274,7 @@ let # Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes reconstructPackageLock = writeTextFile { - name = "addintegrityfields.js"; + name = "reconstructpackagelock.js"; text = '' var fs = require('fs'); var path = require('path'); @@ -280,25 +284,43 @@ let var lockObj = { name: packageObj.name, version: packageObj.version, - lockfileVersion: 1, + lockfileVersion: 2, requires: true, + packages: { + "": { + name: packageObj.name, + version: packageObj.version, + license: packageObj.license, + bin: packageObj.bin, + dependencies: packageObj.dependencies, + engines: packageObj.engines, + optionalDependencies: packageObj.optionalDependencies + } + }, dependencies: {} }; - function augmentPackageJSON(filePath, dependencies) { + function augmentPackageJSON(filePath, packages, dependencies) { var packageJSON = path.join(filePath, "package.json"); if(fs.existsSync(packageJSON)) { var packageObj = JSON.parse(fs.readFileSync(packageJSON)); + packages[filePath] = { + version: packageObj.version, + integrity: "sha1-000000000000000000000000000=", + dependencies: packageObj.dependencies, + engines: packageObj.engines, + optionalDependencies: packageObj.optionalDependencies + }; dependencies[packageObj.name] = { version: packageObj.version, integrity: "sha1-000000000000000000000000000=", dependencies: {} }; - processDependencies(path.join(filePath, "node_modules"), dependencies[packageObj.name].dependencies); + processDependencies(path.join(filePath, "node_modules"), packages, dependencies[packageObj.name].dependencies); } } - function processDependencies(dir, dependencies) { + function processDependencies(dir, packages, dependencies) { if(fs.existsSync(dir)) { var files = fs.readdirSync(dir); @@ -314,23 +336,84 @@ let pkgFiles.forEach(function(entry) { if(stats.isDirectory()) { var pkgFilePath = path.join(filePath, entry); - augmentPackageJSON(pkgFilePath, dependencies); + augmentPackageJSON(pkgFilePath, packages, dependencies); } }); } else { - augmentPackageJSON(filePath, dependencies); + augmentPackageJSON(filePath, packages, dependencies); } } }); } } - processDependencies("node_modules", lockObj.dependencies); + processDependencies("node_modules", lockObj.packages, lockObj.dependencies); fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2)); ''; }; + # Script that links bins defined in package.json to the node_modules bin directory + # NPM does not do this for top-level packages itself anymore as of v7 + linkBinsScript = writeTextFile { + name = "linkbins.js"; + text = '' + var fs = require('fs'); + var path = require('path'); + + var packageObj = JSON.parse(fs.readFileSync("package.json")); + + var nodeModules = Array(packageObj.name.split("/").length).fill("..").join(path.sep); + + if(packageObj.bin !== undefined) { + fs.mkdirSync(path.join(nodeModules, ".bin")) + + if(typeof packageObj.bin == "object") { + Object.keys(packageObj.bin).forEach(function(exe) { + if(fs.existsSync(packageObj.bin[exe])) { + console.log("linking bin '" + exe + "'"); + fs.symlinkSync( + path.join("..", packageObj.name, packageObj.bin[exe]), + path.join(nodeModules, ".bin", exe) + ); + } + else { + console.log("skipping non-existent bin '" + exe + "'"); + } + }) + } + else { + if(fs.existsSync(packageObj.bin)) { + console.log("linking bin '" + packageObj.bin + "'"); + fs.symlinkSync( + path.join("..", packageObj.name, packageObj.bin), + path.join(nodeModules, ".bin", packageObj.name.split("/").pop()) + ); + } + else { + console.log("skipping non-existent bin '" + packageObj.bin + "'"); + } + } + } + else if(packageObj.directories !== undefined && packageObj.directories.bin !== undefined) { + fs.mkdirSync(path.join(nodeModules, ".bin")) + + fs.readdirSync(packageObj.directories.bin).forEach(function(exe) { + if(fs.existsSync(path.join(packageObj.directories.bin, exe))) { + console.log("linking bin '" + exe + "'"); + fs.symlinkSync( + path.join("..", packageObj.name, packageObj.directories.bin, exe), + path.join(nodeModules, ".bin", exe) + ); + } + else { + console.log("skipping non-existent bin '" + exe + "'"); + } + }) + } + ''; + }; + prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}: let forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com"; @@ -377,13 +460,18 @@ let npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} rebuild + runHook postRebuild + if [ "''${dontNpmInstall-}" != "1" ] then # NPM tries to download packages even when they already exist if npm-shrinkwrap is used. rm -f npm-shrinkwrap.json - npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} install + npm ${forceOfflineFlag} --nodedir=${nodeSources} --no-bin-links --ignore-scripts ${npmFlags} ${lib.optionalString production "--production"} install fi + + # Link executables defined in package.json + node ${linkBinsScript} ''; # Builds and composes an NPM package including all its dependencies diff --git a/node-packages.nix b/node-packages.nix index 57b3760..98539dc 100644 --- a/node-packages.nix +++ b/node-packages.nix @@ -382,13 +382,13 @@ let sha512 = "J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="; }; }; - "minimist-1.2.6" = { + "minimist-1.2.7" = { name = "minimist"; packageName = "minimist"; - version = "1.2.6"; + version = "1.2.7"; src = fetchurl { - url = "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz"; - sha512 = "Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="; + url = "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz"; + sha512 = "bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="; }; }; "mkdirp-0.5.6" = { @@ -744,6 +744,7 @@ let sources."finalhandler-0.4.0" sources."forwarded-0.1.2" sources."fresh-0.3.0" + sources."glob-6.0.4" sources."http-errors-1.3.1" sources."inflight-1.0.6" sources."inherits-2.0.4" @@ -755,19 +756,12 @@ let sources."mime-1.3.4" sources."mime-db-1.52.0" sources."mime-types-2.1.35" + sources."minimatch-3.1.2" + sources."minimist-1.2.7" + sources."mkdirp-0.5.6" sources."ms-0.7.1" - (sources."multer-1.1.0" // { - dependencies = [ - sources."minimist-1.2.6" - sources."mkdirp-0.5.6" - ]; - }) - (sources."mv-2.1.1" // { - dependencies = [ - sources."minimist-1.2.6" - sources."mkdirp-0.5.6" - ]; - }) + sources."multer-1.1.0" + sources."mv-2.1.1" sources."ncp-2.0.0" sources."negotiator-0.5.3" sources."object-assign-3.0.0" @@ -781,12 +775,7 @@ let sources."qs-4.0.0" sources."range-parser-1.0.3" sources."readable-stream-1.1.14" - (sources."rimraf-2.4.5" // { - dependencies = [ - sources."glob-6.0.4" - sources."minimatch-3.1.2" - ]; - }) + sources."rimraf-2.4.5" sources."safe-buffer-5.1.2" sources."send-0.13.0" (sources."serve-static-1.10.3" // { @@ -814,7 +803,7 @@ let }; production = true; bypassCache = true; - reconstructLock = false; + reconstructLock = true; }; in {