Skip to content

Commit

Permalink
feat(core): load native files from tmp location instead of node_modules
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKless committed Apr 16, 2024
1 parent 2ee9650 commit 794752c
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 260 deletions.
4 changes: 4 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
{
"group": ["nx/src/plugins/js*"],
"message": "Imports from 'nx/src/plugins/js' are not allowed. Use '@nx/js' instead"
},
{
"group": ["**/native-bindings", "**/native-bindings.js", ""],
"message": "Direct imports from native-bindings.js are not allowed. Import from index.js instead."
}
]
}
Expand Down
4 changes: 4 additions & 0 deletions packages/nx/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
{
"group": ["nx/*"],
"message": "Circular import in 'nx' found. Use relative path."
},
{
"group": ["**/native-bindings", "**/native-bindings.js"],
"message": "Direct imports from native-bindings.js are not allowed. Import from index.js instead."
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion packages/nx/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"executor": "@monodon/rust:napi",
"options": {
"dist": "packages/nx/src/native",
"jsFile": "packages/nx/src/native/index.js",
"jsFile": "packages/nx/src/native/native-bindings.js",
"release": true
},
"configurations": {
Expand Down
322 changes: 63 additions & 259 deletions packages/nx/src/native/index.js
Original file line number Diff line number Diff line change
@@ -1,268 +1,72 @@
const { existsSync, readFileSync } = require('fs')
const { join } = require('path')
const { join, basename } = require('path');
const { copyFileSync, existsSync, mkdirSync } = require('fs');
const Module = require('module');
const { cacheDir } = require("../utils/cache-directory.js")
const { nxVersion } = require('../utils/versions.js');

const { platform, arch } = process
const nxPackages = [
'@nx/nx-android-arm64',
'@nx/nx-android-arm-eabi',
'@nx/nx-win32-x64-msvc',
'@nx/nx-win32-ia32-msvc',
'@nx/nx-win32-arm64-msvc',
'@nx/nx-darwin-universal',
'@nx/nx-darwin-x64',
'@nx/nx-darwin-arm64',
'@nx/nx-freebsd-x64',
'@nx/nx-linux-x64-musl',
'@nx/nx-linux-x64-gnu',
'@nx/nx-linux-arm64-musl',
'@nx/nx-linux-arm64-gnu',
'@nx/nx-linux-arm-gnueabihf',
];

let nativeBinding = null
let localFileExisted = false
let loadError = null
const localNodeFiles = [
'nx.android-arm64.node',
'nx.android-arm-eabi.node',
'nx.win32-x64-msvc.node',
'nx.win32-ia32-msvc.node',
'nx.win32-arm64-msvc.node',
'nx.darwin-universal.node',
'nx.darwin-x64.node',
'nx.darwin-arm64.node',
'nx.freebsd-x64.node',
'nx.linux-x64-musl.node',
'nx.linux-x64-gnu.node',
'nx.linux-arm64-musl.node',
'nx.linux-arm64-gnu.node',
'nx.linux-arm-gnueabihf.node',
];

function isMusl() {
// For Node 10
if (!process.report || typeof process.report.getReport !== 'function') {
try {
const lddPath = require('child_process').execSync('which ldd').toString().trim();
return readFileSync(lddPath, 'utf8').includes('musl')
} catch (e) {
return true
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header
return !glibcVersionRuntime
}
}
const originalLoad = Module._load;

switch (platform) {
case 'android':
switch (arch) {
case 'arm64':
localFileExisted = existsSync(join(__dirname, 'nx.android-arm64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nx.android-arm64.node')
} else {
nativeBinding = require('@nx/nx-android-arm64')
}
} catch (e) {
loadError = e
}
break
case 'arm':
localFileExisted = existsSync(join(__dirname, 'nx.android-arm-eabi.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nx.android-arm-eabi.node')
} else {
nativeBinding = require('@nx/nx-android-arm-eabi')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Android ${arch}`)
}
break
case 'win32':
switch (arch) {
case 'x64':
localFileExisted = existsSync(
join(__dirname, 'nx.win32-x64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nx.win32-x64-msvc.node')
} else {
nativeBinding = require('@nx/nx-win32-x64-msvc')
}
} catch (e) {
loadError = e
}
break
case 'ia32':
localFileExisted = existsSync(
join(__dirname, 'nx.win32-ia32-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nx.win32-ia32-msvc.node')
} else {
nativeBinding = require('@nx/nx-win32-ia32-msvc')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'nx.win32-arm64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nx.win32-arm64-msvc.node')
} else {
nativeBinding = require('@nx/nx-win32-arm64-msvc')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`)
}
break
case 'darwin':
localFileExisted = existsSync(join(__dirname, 'nx.darwin-universal.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nx.darwin-universal.node')
} else {
nativeBinding = require('@nx/nx-darwin-universal')
}
break
} catch {}
switch (arch) {
case 'x64':
localFileExisted = existsSync(join(__dirname, 'nx.darwin-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nx.darwin-x64.node')
} else {
nativeBinding = require('@nx/nx-darwin-x64')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'nx.darwin-arm64.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nx.darwin-arm64.node')
} else {
nativeBinding = require('@nx/nx-darwin-arm64')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`)
Module._load = function (request, parent, isMain) {
const modulePath = request;
if (
nxPackages.includes(modulePath) ||
localNodeFiles.some((f) => modulePath.endsWith(f))
) {
const nativeLocation = require.resolve(modulePath);
const fileName = basename(nativeLocation)

const tmpFile = join(cacheDir, nxVersion + '-' + fileName);
if (existsSync(tmpFile)) {
return originalLoad.apply(this, [tmpFile, parent, isMain]);
}
break
case 'freebsd':
if (arch !== 'x64') {
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
if (!existsSync(cacheDir)) {
mkdirSync(cacheDir, { recursive: true });
}
localFileExisted = existsSync(join(__dirname, 'nx.freebsd-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nx.freebsd-x64.node')
} else {
nativeBinding = require('@nx/nx-freebsd-x64')
}
} catch (e) {
loadError = e
}
break
case 'linux':
switch (arch) {
case 'x64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'nx.linux-x64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nx.linux-x64-musl.node')
} else {
nativeBinding = require('@nx/nx-linux-x64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'nx.linux-x64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nx.linux-x64-gnu.node')
} else {
nativeBinding = require('@nx/nx-linux-x64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'nx.linux-arm64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nx.linux-arm64-musl.node')
} else {
nativeBinding = require('@nx/nx-linux-arm64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'nx.linux-arm64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nx.linux-arm64-gnu.node')
} else {
nativeBinding = require('@nx/nx-linux-arm64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm':
localFileExisted = existsSync(
join(__dirname, 'nx.linux-arm-gnueabihf.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nx.linux-arm-gnueabihf.node')
} else {
nativeBinding = require('@nx/nx-linux-arm-gnueabihf')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Linux: ${arch}`)
}
break
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
}

if (!nativeBinding) {
if (loadError) {
throw loadError
copyFileSync(nativeLocation, tmpFile);
return originalLoad.apply(this, [tmpFile, parent, isMain]);
} else {
return originalLoad.apply(this, arguments);
}
throw new Error(`Failed to load native binding`)
}
};

const indexModulePath = require.resolve('./native-bindings.js');
delete require.cache[indexModulePath];
const indexModule = require('./native-bindings.js');

const { expandOutputs, getFilesForOutputs, remove, copy, hashArray, hashFile, ImportResult, findImports, transferProjectGraph, ChildProcess, RustPseudoTerminal, HashPlanner, TaskHasher, EventType, Watcher, WorkspaceContext, WorkspaceErrors, testOnlyTransferFileMap } = nativeBinding

module.exports.expandOutputs = expandOutputs
module.exports.getFilesForOutputs = getFilesForOutputs
module.exports.remove = remove
module.exports.copy = copy
module.exports.hashArray = hashArray
module.exports.hashFile = hashFile
module.exports.ImportResult = ImportResult
module.exports.findImports = findImports
module.exports.transferProjectGraph = transferProjectGraph
module.exports.ChildProcess = ChildProcess
module.exports.RustPseudoTerminal = RustPseudoTerminal
module.exports.HashPlanner = HashPlanner
module.exports.TaskHasher = TaskHasher
module.exports.EventType = EventType
module.exports.Watcher = Watcher
module.exports.WorkspaceContext = WorkspaceContext
module.exports.WorkspaceErrors = WorkspaceErrors
module.exports.testOnlyTransferFileMap = testOnlyTransferFileMap
module.exports = indexModule;
Module._load = originalLoad;
Loading

0 comments on commit 794752c

Please sign in to comment.