@companion-module/tools 2.4.2 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/package.json +25 -16
- package/scripts/build-connection.js +22 -0
- package/scripts/build-surface.js +22 -0
- package/scripts/check-surface.js +40 -0
- package/scripts/lib/build-util.js +237 -0
- package/tsconfig/node22/recommended-esm.json +30 -0
- package/webpack.config.cjs +15 -5
- package/scripts/build.js +0 -250
- /package/scripts/{check.js → check-connection.js} +0 -0
- /package/scripts/{generate-manifest.js → generate-connection-manifest.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.6.0](https://github.com/bitfocus/companion-module-tools/compare/v2.5.0...v2.6.0) (2026-01-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add `@companion-module/tools/tsconfig/node22/recommended-esm` tsconfig ([3fec18c](https://github.com/bitfocus/companion-module-tools/commit/3fec18c8db8c38c9246b36d458aa59d56f49c108))
|
|
9
|
+
|
|
10
|
+
## [2.5.0](https://github.com/bitfocus/companion-module-tools/compare/v2.4.2...v2.5.0) (2025-12-15)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* add support for building surface modules ([55721fe](https://github.com/bitfocus/companion-module-tools/commit/55721fe9282128485021385065b17d32439167d8))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* surface module build ([36bfae9](https://github.com/bitfocus/companion-module-tools/commit/36bfae9cfbbafc00ed81dd6f1082bedbe02e2e89))
|
|
21
|
+
|
|
3
22
|
## [2.4.2](https://github.com/bitfocus/companion-module-tools/compare/v2.4.1...v2.4.2) (2025-10-18)
|
|
4
23
|
|
|
5
24
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@companion-module/tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
"url": "git+https://github.com/bitfocus/companion-module-tools.git"
|
|
10
10
|
},
|
|
11
11
|
"bin": {
|
|
12
|
-
"companion-generate-manifest": "scripts/generate-manifest.js",
|
|
13
|
-
"companion-module-build": "scripts/build.js",
|
|
14
|
-
"companion-module-check": "scripts/check.js"
|
|
12
|
+
"companion-generate-manifest": "scripts/generate-connection-manifest.js",
|
|
13
|
+
"companion-module-build": "scripts/build-connection.js",
|
|
14
|
+
"companion-module-check": "scripts/check-connection.js",
|
|
15
|
+
"companion-surface-build": "scripts/build-surface.js",
|
|
16
|
+
"companion-surface-check": "scripts/check-surface.js"
|
|
15
17
|
},
|
|
16
18
|
"engines": {
|
|
17
19
|
"node": "^18.18 || ^22.18"
|
|
@@ -26,25 +28,32 @@
|
|
|
26
28
|
"webpack.*"
|
|
27
29
|
],
|
|
28
30
|
"dependencies": {
|
|
29
|
-
"@eslint/js": "^9.
|
|
31
|
+
"@eslint/js": "^9.39.2",
|
|
30
32
|
"eslint-config-prettier": "^10.1.8",
|
|
31
|
-
"eslint-plugin-n": "^17.23.
|
|
32
|
-
"eslint-plugin-prettier": "^5.5.
|
|
33
|
-
"find-up": "^
|
|
33
|
+
"eslint-plugin-n": "^17.23.2",
|
|
34
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
35
|
+
"find-up": "^8.0.0",
|
|
34
36
|
"parse-author": "^2.0.0",
|
|
35
|
-
"semver": "^7.7.
|
|
36
|
-
"tar": "^7.5.
|
|
37
|
-
"webpack": "^5.
|
|
37
|
+
"semver": "^7.7.3",
|
|
38
|
+
"tar": "^7.5.7",
|
|
39
|
+
"webpack": "^5.104.1",
|
|
38
40
|
"webpack-cli": "^6.0.1",
|
|
39
|
-
"zx": "^8.8.
|
|
41
|
+
"zx": "^8.8.5"
|
|
40
42
|
},
|
|
41
43
|
"peerDependencies": {
|
|
42
44
|
"@companion-module/base": "^1.12.0",
|
|
45
|
+
"@companion-surface/base": "^1.0.0",
|
|
43
46
|
"eslint": "^9.36.0",
|
|
44
47
|
"prettier": "^3.6.2",
|
|
45
48
|
"typescript-eslint": "^8.44.1"
|
|
46
49
|
},
|
|
47
50
|
"peerDependenciesMeta": {
|
|
51
|
+
"@companion-module/base": {
|
|
52
|
+
"optional": true
|
|
53
|
+
},
|
|
54
|
+
"@companion-surface/base": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
48
57
|
"eslint": {
|
|
49
58
|
"optional": true
|
|
50
59
|
},
|
|
@@ -57,9 +66,9 @@
|
|
|
57
66
|
},
|
|
58
67
|
"devDependencies": {
|
|
59
68
|
"@types/eslint": "^9.6.1",
|
|
60
|
-
"eslint": "^9.
|
|
61
|
-
"prettier": "^3.
|
|
62
|
-
"typescript-eslint": "^8.
|
|
69
|
+
"eslint": "^9.39.2",
|
|
70
|
+
"prettier": "^3.8.1",
|
|
71
|
+
"typescript-eslint": "^8.54.0"
|
|
63
72
|
},
|
|
64
|
-
"packageManager": "yarn@4.
|
|
73
|
+
"packageManager": "yarn@4.12.0"
|
|
65
74
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The zx shebang doesn't resolve dependencies correctly
|
|
3
|
+
import 'zx/globals'
|
|
4
|
+
|
|
5
|
+
import { buildPackage } from './lib/build-util.js'
|
|
6
|
+
|
|
7
|
+
if (process.platform === 'win32') {
|
|
8
|
+
usePowerShell() // to enable powershell
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (argv.help) {
|
|
12
|
+
console.log('Usage: companion-module-build [--dev] [--prerelease]')
|
|
13
|
+
console.log('Builds the companion connection module')
|
|
14
|
+
console.log(' --dev: Build in development mode. This will not minify the code, making it easier to debug.')
|
|
15
|
+
console.log(' --prerelease: Build in prerelease mode. This gets added as metadata to the manifest')
|
|
16
|
+
console.log(' --output <filename>: Output to a specific filename, without a file extension')
|
|
17
|
+
process.exit(0)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { validateManifest } = await import('@companion-module/base')
|
|
21
|
+
|
|
22
|
+
await buildPackage('@companion-module/base', validateManifest, 'connection')
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The zx shebang doesn't resolve dependencies correctly
|
|
3
|
+
import 'zx/globals'
|
|
4
|
+
|
|
5
|
+
import { buildPackage } from './lib/build-util.js'
|
|
6
|
+
|
|
7
|
+
if (process.platform === 'win32') {
|
|
8
|
+
usePowerShell() // to enable powershell
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (argv.help) {
|
|
12
|
+
console.log('Usage: companion-module-build [--dev] [--prerelease]')
|
|
13
|
+
console.log('Builds the companion connection module')
|
|
14
|
+
console.log(' --dev: Build in development mode. This will not minify the code, making it easier to debug.')
|
|
15
|
+
console.log(' --prerelease: Build in prerelease mode. This gets added as metadata to the manifest')
|
|
16
|
+
console.log(' --output <filename>: Output to a specific filename, without a file extension')
|
|
17
|
+
process.exit(0)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { validateSurfaceManifest } = await import('@companion-surface/base')
|
|
21
|
+
|
|
22
|
+
await buildPackage('@companion-surface/base', validateSurfaceManifest, 'surface')
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The zx shebang doesn't resolve dependencies correctly
|
|
3
|
+
import 'zx/globals'
|
|
4
|
+
|
|
5
|
+
import path from 'path'
|
|
6
|
+
import { fs } from 'zx'
|
|
7
|
+
import { findUp } from 'find-up'
|
|
8
|
+
import { validateSurfaceManifest } from '@companion-surface/base'
|
|
9
|
+
import { createRequire } from 'module'
|
|
10
|
+
|
|
11
|
+
if (process.platform === 'win32') {
|
|
12
|
+
usePowerShell() // to enable powershell
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const require = createRequire(import.meta.url)
|
|
16
|
+
|
|
17
|
+
async function findModuleDir(cwd) {
|
|
18
|
+
const stat = await fs.stat(cwd)
|
|
19
|
+
if (stat.isFile()) cwd = path.dirname(cwd)
|
|
20
|
+
|
|
21
|
+
const pkgJsonPath = await findUp('package.json', { cwd })
|
|
22
|
+
return path.dirname(pkgJsonPath)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// const toolsDir = path.join(__dirname, '..')
|
|
26
|
+
const toolsDir = await findModuleDir(require.resolve('@companion-module/tools'))
|
|
27
|
+
const frameworkDir = await findModuleDir(require.resolve('@companion-surface/base'))
|
|
28
|
+
console.log(`Checking for: ${process.cwd()}`)
|
|
29
|
+
|
|
30
|
+
console.log(`Tools path: ${toolsDir}`)
|
|
31
|
+
console.log(`Framework path: ${frameworkDir}`)
|
|
32
|
+
|
|
33
|
+
const manifestJson = JSON.parse(await fs.readFile(path.resolve('./companion/manifest.json')))
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
validateSurfaceManifest(manifestJson)
|
|
37
|
+
} catch (e) {
|
|
38
|
+
console.error('Manifest validation failed', e)
|
|
39
|
+
process.exit(1)
|
|
40
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import 'zx/globals'
|
|
2
|
+
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { fs } from 'zx'
|
|
5
|
+
import { findUp } from 'find-up'
|
|
6
|
+
import * as tar from 'tar'
|
|
7
|
+
import { createRequire } from 'module'
|
|
8
|
+
import * as semver from 'semver'
|
|
9
|
+
|
|
10
|
+
function toSanitizedDirname(name) {
|
|
11
|
+
return name.replace(/[^a-zA-Z0-9-\.]/g, '-').replace(/[-+]/g, '-')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const require = createRequire(import.meta.url)
|
|
15
|
+
|
|
16
|
+
async function findModuleDir(cwd) {
|
|
17
|
+
const stat = await fs.stat(cwd)
|
|
18
|
+
if (stat.isFile()) cwd = path.dirname(cwd)
|
|
19
|
+
|
|
20
|
+
const pkgJsonPath = await findUp('package.json', { cwd })
|
|
21
|
+
return path.dirname(pkgJsonPath)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function buildPackage(frameworkPackageName, validateManifest, moduleType) {
|
|
25
|
+
// const toolsDir = path.join(__dirname, '..')
|
|
26
|
+
const moduleDir = process.cwd()
|
|
27
|
+
const toolsDir = await findModuleDir(require.resolve('@companion-module/tools'))
|
|
28
|
+
const frameworkDir = await findModuleDir(require.resolve(frameworkPackageName))
|
|
29
|
+
console.log(`Building for: ${process.cwd()}`)
|
|
30
|
+
|
|
31
|
+
console.log(`Tools path: ${toolsDir}`)
|
|
32
|
+
console.log(`Framework path: ${frameworkDir}`)
|
|
33
|
+
|
|
34
|
+
// clean old
|
|
35
|
+
await fs.remove('pkg')
|
|
36
|
+
|
|
37
|
+
// create new
|
|
38
|
+
await fs.mkdir(`pkg`)
|
|
39
|
+
|
|
40
|
+
const packageBaseDir = path.join('pkg')
|
|
41
|
+
|
|
42
|
+
const webpackArgs = {
|
|
43
|
+
ROOT: moduleDir,
|
|
44
|
+
MODULETYPE: moduleType,
|
|
45
|
+
}
|
|
46
|
+
if (argv.dev || argv.debug) webpackArgs['dev'] = true
|
|
47
|
+
|
|
48
|
+
const webpackArgsArray = []
|
|
49
|
+
for (const [k, v] of Object.entries(webpackArgs)) {
|
|
50
|
+
webpackArgsArray.push(`--env`, v === true ? k : `${k}=${v}`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// build the code
|
|
54
|
+
$.cwd = toolsDir
|
|
55
|
+
const webpackConfig = path.join(toolsDir, 'webpack.config.cjs').replace(/\\/g, '/') // Fix slashes because windows is a pain
|
|
56
|
+
// use npx to invoke. manual paths does not work on windows, and using `yarn` requires corepack
|
|
57
|
+
await $`npx webpack -c ${webpackConfig} ${webpackArgsArray}`
|
|
58
|
+
$.cwd = undefined
|
|
59
|
+
|
|
60
|
+
// copy in the metadata
|
|
61
|
+
await fs.copy('companion', path.join(packageBaseDir, 'companion'))
|
|
62
|
+
|
|
63
|
+
const srcPackageJson = JSON.parse(await fs.readFile(path.resolve('./package.json')))
|
|
64
|
+
const frameworkPackageJson = JSON.parse(await fs.readFile(path.join(frameworkDir, 'package.json')))
|
|
65
|
+
|
|
66
|
+
// Copy the manifest, overriding some properties
|
|
67
|
+
const manifestJson = JSON.parse(await fs.readFile(path.resolve('./companion/manifest.json')))
|
|
68
|
+
manifestJson.runtime.entrypoint = '../main.js'
|
|
69
|
+
manifestJson.version = srcPackageJson.version
|
|
70
|
+
manifestJson.runtime.api = 'nodejs-ipc'
|
|
71
|
+
manifestJson.runtime.apiVersion = frameworkPackageJson.version
|
|
72
|
+
|
|
73
|
+
// Bake in the prerelease flag if using module-base which is new enough
|
|
74
|
+
if (semver.gt(manifestJson.runtime.apiVersion, '1.12.0-0')) {
|
|
75
|
+
manifestJson.isPrerelease = !!argv.prerelease
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await fs.writeFile(path.join(packageBaseDir, 'companion/manifest.json'), JSON.stringify(manifestJson))
|
|
79
|
+
|
|
80
|
+
// Make sure the manifest is valid
|
|
81
|
+
try {
|
|
82
|
+
validateManifest(manifestJson)
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.error('Manifest validation failed', e)
|
|
85
|
+
process.exit(1)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Generate a minimal package.json
|
|
89
|
+
const packageJson = {
|
|
90
|
+
name: moduleType === 'connection' ? manifestJson.name : manifestJson.id,
|
|
91
|
+
version: manifestJson.version,
|
|
92
|
+
license: manifestJson.license,
|
|
93
|
+
// Minimal content
|
|
94
|
+
type: 'commonjs',
|
|
95
|
+
dependencies: {},
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Ensure that any externals are added as dependencies
|
|
99
|
+
const webpackExtPath = path.resolve('build-config.cjs')
|
|
100
|
+
if (fs.existsSync(webpackExtPath)) {
|
|
101
|
+
const webpackExt = require(webpackExtPath)
|
|
102
|
+
|
|
103
|
+
// Add any external dependencies, with versions matching what is currntly installed
|
|
104
|
+
if (webpackExt.externals) {
|
|
105
|
+
const extArray = Array.isArray(webpackExt.externals) ? webpackExt.externals : [webpackExt.externals]
|
|
106
|
+
for (const extGroup of extArray) {
|
|
107
|
+
if (typeof extGroup === 'object') {
|
|
108
|
+
// TODO - does this need to be a stricter object check?
|
|
109
|
+
|
|
110
|
+
for (const external of Object.keys(extGroup)) {
|
|
111
|
+
const extPath = await findUp('package.json', { cwd: require.resolve(external) })
|
|
112
|
+
const extJson = JSON.parse(await fs.readFile(extPath))
|
|
113
|
+
packageJson.dependencies[extJson.name] = extJson.version
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (webpackExt.forceRemoveNodeGypFromPkg) {
|
|
120
|
+
packageJson.resolutions = {
|
|
121
|
+
'node-gyp': 'npm:empty-npm-package@1.0.0',
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Copy across any prebuilds that can be loaded corectly
|
|
126
|
+
if (webpackExt.prebuilds) {
|
|
127
|
+
await fs.mkdir(path.join(packageBaseDir, 'prebuilds'))
|
|
128
|
+
|
|
129
|
+
for (const lib of webpackExt.prebuilds) {
|
|
130
|
+
const srcDir = await findModuleDir(require.resolve(lib))
|
|
131
|
+
const filesOrDirs = await fs.readdir(path.join(srcDir, 'prebuilds'))
|
|
132
|
+
for (const fileOrDir of filesOrDirs) {
|
|
133
|
+
await fs.copy(path.join(srcDir, 'prebuilds', fileOrDir), path.join(packageBaseDir, 'prebuilds', fileOrDir))
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// copy extra files
|
|
139
|
+
if (Array.isArray(webpackExt.extraFiles)) {
|
|
140
|
+
const files = await globby(webpackExt.extraFiles, {
|
|
141
|
+
expandDirectories: false,
|
|
142
|
+
onlyFiles: false,
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
await fs.copy(file, path.join(packageBaseDir, path.basename(file)), {
|
|
147
|
+
overwrite: false,
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Copy node-gyp-build prebulds
|
|
154
|
+
const webpackConfigJson = await require(webpackConfig)(webpackArgs)
|
|
155
|
+
if (webpackConfigJson.node?.__dirname === true) {
|
|
156
|
+
const copyNodeGypBuildPrebuilds = (thisPath) => {
|
|
157
|
+
const nodeModPath = path.join(thisPath, 'node_modules')
|
|
158
|
+
if (fs.existsSync(nodeModPath)) {
|
|
159
|
+
for (const dir of fs.readdirSync(nodeModPath)) {
|
|
160
|
+
const modDir = path.join(nodeModPath, dir)
|
|
161
|
+
copyNodeGypBuildPrebuilds(modDir)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const pkgJsonPath = path.join(thisPath, 'package.json')
|
|
166
|
+
if (thisPath && fs.existsSync(pkgJsonPath)) {
|
|
167
|
+
const dirPkgJsonStr = fs.readFileSync(pkgJsonPath)
|
|
168
|
+
const dirPkgJson = JSON.parse(dirPkgJsonStr.toString())
|
|
169
|
+
|
|
170
|
+
const prebuildsDir = path.join(thisPath, 'prebuilds')
|
|
171
|
+
if (dirPkgJson.dependencies?.['node-gyp-build'] && fs.existsSync(prebuildsDir)) {
|
|
172
|
+
fs.mkdirpSync(path.join(packageBaseDir, thisPath))
|
|
173
|
+
fs.copySync(prebuildsDir, path.join(packageBaseDir, prebuildsDir))
|
|
174
|
+
|
|
175
|
+
console.log('copying node-gyp-build prebuilds from', thisPath)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
copyNodeGypBuildPrebuilds('')
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Write the package.json
|
|
184
|
+
// packageJson.bundleDependencies = Object.keys(packageJson.dependencies)
|
|
185
|
+
await fs.writeFile(path.join(packageBaseDir, 'package.json'), JSON.stringify(packageJson))
|
|
186
|
+
|
|
187
|
+
// If we found any depenendencies for the pkg, install them
|
|
188
|
+
if (Object.keys(packageJson.dependencies).length) {
|
|
189
|
+
await fs.writeFile(path.join(packageBaseDir, 'yarn.lock'), '')
|
|
190
|
+
await $`yarn --cwd ${packageBaseDir} install --no-immutable`
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Prune any excessive prebuilds
|
|
194
|
+
const prebuildDirName = path.join(packageBaseDir, 'prebuilds')
|
|
195
|
+
if (fs.existsSync(prebuildDirName)) {
|
|
196
|
+
const prebuildDirs = await fs.readdir(prebuildDirName)
|
|
197
|
+
for (const dir of prebuildDirs) {
|
|
198
|
+
let keepDir = true
|
|
199
|
+
if (dir.match(/freebsd/) || dir.match(/android/)) {
|
|
200
|
+
// Unsupported platforms
|
|
201
|
+
keepDir = false
|
|
202
|
+
} else if (dir.match(/win32-ia32/)) {
|
|
203
|
+
// 32bit windows is not supported
|
|
204
|
+
keepDir = false
|
|
205
|
+
} else if (dir.match(/linux(.+)musl/)) {
|
|
206
|
+
// linux musl is not supported
|
|
207
|
+
keepDir = false
|
|
208
|
+
} else if (dir.match(/linux-arm$/) || dir.match(/linux-arm-gnueabihf/)) {
|
|
209
|
+
// linux arm (non arm64) is not supported
|
|
210
|
+
keepDir = false
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!keepDir) {
|
|
214
|
+
console.log('Removing unneeded prebuild dir:', dir)
|
|
215
|
+
await fs.rm(path.join(prebuildDirName, dir), { recursive: true, force: true })
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Create tgz of the build
|
|
221
|
+
let tgzFile = toSanitizedDirname(`${manifestJson.id}-${manifestJson.version}`)
|
|
222
|
+
if (typeof argv['output'] === 'string') {
|
|
223
|
+
// -o flag, to allow legacy behaviour creating pkg.tgz output
|
|
224
|
+
tgzFile = argv['output']
|
|
225
|
+
}
|
|
226
|
+
tgzFile += '.tgz'
|
|
227
|
+
console.log('Writing compressed package output to', tgzFile)
|
|
228
|
+
|
|
229
|
+
await tar
|
|
230
|
+
.create(
|
|
231
|
+
{
|
|
232
|
+
gzip: true,
|
|
233
|
+
},
|
|
234
|
+
[packageBaseDir],
|
|
235
|
+
)
|
|
236
|
+
.pipe(fs.createWriteStream(tgzFile))
|
|
237
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "node20",
|
|
4
|
+
"target": "es2024",
|
|
5
|
+
"noImplicitAny": true,
|
|
6
|
+
"moduleResolution": "node16",
|
|
7
|
+
"sourceMap": true,
|
|
8
|
+
"paths": {
|
|
9
|
+
"*": ["../node_modules/*"]
|
|
10
|
+
},
|
|
11
|
+
"declaration": false,
|
|
12
|
+
"importHelpers": false,
|
|
13
|
+
"listFiles": false,
|
|
14
|
+
"traceResolution": false,
|
|
15
|
+
"pretty": true,
|
|
16
|
+
"lib": ["es2024"],
|
|
17
|
+
"types": ["node"],
|
|
18
|
+
"strict": true,
|
|
19
|
+
"alwaysStrict": false,
|
|
20
|
+
"forceConsistentCasingInFileNames": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
"noImplicitReturns": true,
|
|
23
|
+
"noUnusedLocals": true,
|
|
24
|
+
"noUnusedParameters": true,
|
|
25
|
+
"skipLibCheck": true,
|
|
26
|
+
"allowSyntheticDefaultImports": true,
|
|
27
|
+
"esModuleInterop": true
|
|
28
|
+
},
|
|
29
|
+
"compileOnSave": false
|
|
30
|
+
}
|
package/webpack.config.cjs
CHANGED
|
@@ -2,8 +2,8 @@ const path = require('path')
|
|
|
2
2
|
|
|
3
3
|
module.exports = async (env) => {
|
|
4
4
|
if (!env.ROOT) throw new Error(`Missing ROOT`)
|
|
5
|
+
if (!env.MODULETYPE) throw new Error(`Missing MODULETYPE`)
|
|
5
6
|
|
|
6
|
-
const frameworkDir = path.relative(env.ROOT, path.resolve('@companion-module/base'))
|
|
7
7
|
const pkgJson = require(path.join(env.ROOT, 'package.json'))
|
|
8
8
|
|
|
9
9
|
if (!pkgJson.main) throw new Error(`Missing main in package.json`)
|
|
@@ -28,10 +28,20 @@ module.exports = async (env) => {
|
|
|
28
28
|
...webpackExt.entry,
|
|
29
29
|
},
|
|
30
30
|
mode: env.dev ? 'development' : 'production',
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
output:
|
|
32
|
+
env.MODULETYPE === 'connection'
|
|
33
|
+
? {
|
|
34
|
+
path: path.resolve(env.ROOT, 'pkg'),
|
|
35
|
+
}
|
|
36
|
+
: {
|
|
37
|
+
path: path.resolve(env.ROOT, 'pkg'),
|
|
38
|
+
filename: 'main.js',
|
|
39
|
+
library: {
|
|
40
|
+
type: 'commonjs2',
|
|
41
|
+
// Avoid producing a double default in the bundle
|
|
42
|
+
export: 'default',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
35
45
|
context: path.resolve(env.ROOT, '.'),
|
|
36
46
|
target: 'node',
|
|
37
47
|
externals: [
|
package/scripts/build.js
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// The zx shebang doesn't resolve dependencies correctly
|
|
3
|
-
import 'zx/globals'
|
|
4
|
-
|
|
5
|
-
import path from 'path'
|
|
6
|
-
import { fs } from 'zx'
|
|
7
|
-
import { findUp } from 'find-up'
|
|
8
|
-
import * as tar from 'tar'
|
|
9
|
-
import { validateManifest } from '@companion-module/base'
|
|
10
|
-
import { createRequire } from 'module'
|
|
11
|
-
import * as semver from 'semver'
|
|
12
|
-
|
|
13
|
-
if (process.platform === 'win32') {
|
|
14
|
-
usePowerShell() // to enable powershell
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (argv.help) {
|
|
18
|
-
console.log('Usage: build.js [--dev] [--prerelease]')
|
|
19
|
-
console.log('Builds the companion module')
|
|
20
|
-
console.log(' --dev: Build in development mode. This will not minify the code, making it easier to debug.')
|
|
21
|
-
console.log(' --prerelease: Build in prerelease mode. This gets added as metadata to the manifest')
|
|
22
|
-
console.log(' --output <filename>: Output to a specific filename, without a file extension')
|
|
23
|
-
process.exit(0)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function toSanitizedDirname(name) {
|
|
27
|
-
return name.replace(/[^a-zA-Z0-9-\.]/g, '-').replace(/[-+]/g, '-')
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const require = createRequire(import.meta.url)
|
|
31
|
-
|
|
32
|
-
async function findModuleDir(cwd) {
|
|
33
|
-
const stat = await fs.stat(cwd)
|
|
34
|
-
if (stat.isFile()) cwd = path.dirname(cwd)
|
|
35
|
-
|
|
36
|
-
const pkgJsonPath = await findUp('package.json', { cwd })
|
|
37
|
-
return path.dirname(pkgJsonPath)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// const toolsDir = path.join(__dirname, '..')
|
|
41
|
-
const moduleDir = process.cwd()
|
|
42
|
-
const toolsDir = await findModuleDir(require.resolve('@companion-module/tools'))
|
|
43
|
-
const frameworkDir = await findModuleDir(require.resolve('@companion-module/base'))
|
|
44
|
-
console.log(`Building for: ${process.cwd()}`)
|
|
45
|
-
|
|
46
|
-
console.log(`Tools path: ${toolsDir}`)
|
|
47
|
-
console.log(`Framework path: ${frameworkDir}`)
|
|
48
|
-
|
|
49
|
-
// clean old
|
|
50
|
-
await fs.remove('pkg')
|
|
51
|
-
|
|
52
|
-
// create new
|
|
53
|
-
await fs.mkdir(`pkg`)
|
|
54
|
-
|
|
55
|
-
const packageBaseDir = path.join('pkg')
|
|
56
|
-
|
|
57
|
-
const webpackArgs = {
|
|
58
|
-
ROOT: moduleDir,
|
|
59
|
-
}
|
|
60
|
-
if (argv.dev || argv.debug) webpackArgs['dev'] = true
|
|
61
|
-
|
|
62
|
-
const webpackArgsArray = []
|
|
63
|
-
for (const [k, v] of Object.entries(webpackArgs)) {
|
|
64
|
-
webpackArgsArray.push(`--env`, v === true ? k : `${k}=${v}`)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// build the code
|
|
68
|
-
$.cwd = toolsDir
|
|
69
|
-
const webpackConfig = path.join(toolsDir, 'webpack.config.cjs').replace(/\\/g, '/') // Fix slashes because windows is a pain
|
|
70
|
-
// use npx to invoke. manual paths does not work on windows, and using `yarn` requires corepack
|
|
71
|
-
await $`npx webpack -c ${webpackConfig} ${webpackArgsArray}`
|
|
72
|
-
$.cwd = undefined
|
|
73
|
-
|
|
74
|
-
// copy in the metadata
|
|
75
|
-
await fs.copy('companion', path.join(packageBaseDir, 'companion'))
|
|
76
|
-
|
|
77
|
-
const srcPackageJson = JSON.parse(await fs.readFile(path.resolve('./package.json')))
|
|
78
|
-
const frameworkPackageJson = JSON.parse(await fs.readFile(path.join(frameworkDir, 'package.json')))
|
|
79
|
-
|
|
80
|
-
// Copy the manifest, overriding some properties
|
|
81
|
-
const manifestJson = JSON.parse(await fs.readFile(path.resolve('./companion/manifest.json')))
|
|
82
|
-
manifestJson.runtime.entrypoint = '../main.js'
|
|
83
|
-
manifestJson.version = srcPackageJson.version
|
|
84
|
-
manifestJson.runtime.api = 'nodejs-ipc'
|
|
85
|
-
manifestJson.runtime.apiVersion = frameworkPackageJson.version
|
|
86
|
-
|
|
87
|
-
// Bake in the prerelease flag if using module-base which is new enough
|
|
88
|
-
if (semver.gt(manifestJson.runtime.apiVersion, '1.12.0-0')) {
|
|
89
|
-
manifestJson.isPrerelease = !!argv.prerelease
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
await fs.writeFile(path.join(packageBaseDir, 'companion/manifest.json'), JSON.stringify(manifestJson))
|
|
93
|
-
|
|
94
|
-
// Make sure the manifest is valid
|
|
95
|
-
try {
|
|
96
|
-
validateManifest(manifestJson)
|
|
97
|
-
} catch (e) {
|
|
98
|
-
console.error('Manifest validation failed', e)
|
|
99
|
-
process.exit(1)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Generate a minimal package.json
|
|
103
|
-
const packageJson = {
|
|
104
|
-
name: manifestJson.name,
|
|
105
|
-
version: manifestJson.version,
|
|
106
|
-
license: manifestJson.license,
|
|
107
|
-
// Minimal content
|
|
108
|
-
type: 'commonjs',
|
|
109
|
-
dependencies: {},
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Ensure that any externals are added as dependencies
|
|
113
|
-
const webpackExtPath = path.resolve('build-config.cjs')
|
|
114
|
-
if (fs.existsSync(webpackExtPath)) {
|
|
115
|
-
const webpackExt = require(webpackExtPath)
|
|
116
|
-
|
|
117
|
-
// Add any external dependencies, with versions matching what is currntly installed
|
|
118
|
-
if (webpackExt.externals) {
|
|
119
|
-
const extArray = Array.isArray(webpackExt.externals) ? webpackExt.externals : [webpackExt.externals]
|
|
120
|
-
for (const extGroup of extArray) {
|
|
121
|
-
if (typeof extGroup === 'object') {
|
|
122
|
-
// TODO - does this need to be a stricter object check?
|
|
123
|
-
|
|
124
|
-
for (const external of Object.keys(extGroup)) {
|
|
125
|
-
const extPath = await findUp('package.json', { cwd: require.resolve(external) })
|
|
126
|
-
const extJson = JSON.parse(await fs.readFile(extPath))
|
|
127
|
-
packageJson.dependencies[extJson.name] = extJson.version
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (webpackExt.forceRemoveNodeGypFromPkg) {
|
|
134
|
-
packageJson.resolutions = {
|
|
135
|
-
'node-gyp': 'npm:empty-npm-package@1.0.0',
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Copy across any prebuilds that can be loaded corectly
|
|
140
|
-
if (webpackExt.prebuilds) {
|
|
141
|
-
await fs.mkdir(path.join(packageBaseDir, 'prebuilds'))
|
|
142
|
-
|
|
143
|
-
for (const lib of webpackExt.prebuilds) {
|
|
144
|
-
const srcDir = await findModuleDir(require.resolve(lib))
|
|
145
|
-
const filesOrDirs = await fs.readdir(path.join(srcDir, 'prebuilds'))
|
|
146
|
-
for (const fileOrDir of filesOrDirs) {
|
|
147
|
-
await fs.copy(path.join(srcDir, 'prebuilds', fileOrDir), path.join(packageBaseDir, 'prebuilds', fileOrDir))
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// copy extra files
|
|
153
|
-
if (Array.isArray(webpackExt.extraFiles)) {
|
|
154
|
-
const files = await globby(webpackExt.extraFiles, {
|
|
155
|
-
expandDirectories: false,
|
|
156
|
-
onlyFiles: false,
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
for (const file of files) {
|
|
160
|
-
await fs.copy(file, path.join(packageBaseDir, path.basename(file)), {
|
|
161
|
-
overwrite: false,
|
|
162
|
-
})
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Copy node-gyp-build prebulds
|
|
168
|
-
const webpackConfigJson = await require(webpackConfig)(webpackArgs)
|
|
169
|
-
if (webpackConfigJson.node?.__dirname === true) {
|
|
170
|
-
const copyNodeGypBuildPrebuilds = (thisPath) => {
|
|
171
|
-
const nodeModPath = path.join(thisPath, 'node_modules')
|
|
172
|
-
if (fs.existsSync(nodeModPath)) {
|
|
173
|
-
for (const dir of fs.readdirSync(nodeModPath)) {
|
|
174
|
-
const modDir = path.join(nodeModPath, dir)
|
|
175
|
-
copyNodeGypBuildPrebuilds(modDir)
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const pkgJsonPath = path.join(thisPath, 'package.json')
|
|
180
|
-
if (thisPath && fs.existsSync(pkgJsonPath)) {
|
|
181
|
-
const dirPkgJsonStr = fs.readFileSync(pkgJsonPath)
|
|
182
|
-
const dirPkgJson = JSON.parse(dirPkgJsonStr.toString())
|
|
183
|
-
|
|
184
|
-
const prebuildsDir = path.join(thisPath, 'prebuilds')
|
|
185
|
-
if (dirPkgJson.dependencies?.['node-gyp-build'] && fs.existsSync(prebuildsDir)) {
|
|
186
|
-
fs.mkdirpSync(path.join(packageBaseDir, thisPath))
|
|
187
|
-
fs.copySync(prebuildsDir, path.join(packageBaseDir, prebuildsDir))
|
|
188
|
-
|
|
189
|
-
console.log('copying node-gyp-build prebuilds from', thisPath)
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
copyNodeGypBuildPrebuilds('')
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Write the package.json
|
|
198
|
-
// packageJson.bundleDependencies = Object.keys(packageJson.dependencies)
|
|
199
|
-
await fs.writeFile(path.join(packageBaseDir, 'package.json'), JSON.stringify(packageJson))
|
|
200
|
-
|
|
201
|
-
// If we found any depenendencies for the pkg, install them
|
|
202
|
-
if (Object.keys(packageJson.dependencies).length) {
|
|
203
|
-
await fs.writeFile(path.join(packageBaseDir, 'yarn.lock'), '')
|
|
204
|
-
await $`yarn --cwd ${packageBaseDir} install --no-immutable`
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Prune any excessive prebuilds
|
|
208
|
-
const prebuildDirName = path.join(packageBaseDir, 'prebuilds')
|
|
209
|
-
if (fs.existsSync(prebuildDirName)) {
|
|
210
|
-
const prebuildDirs = await fs.readdir(prebuildDirName)
|
|
211
|
-
for (const dir of prebuildDirs) {
|
|
212
|
-
let keepDir = true
|
|
213
|
-
if (dir.match(/freebsd/) || dir.match(/android/)) {
|
|
214
|
-
// Unsupported platforms
|
|
215
|
-
keepDir = false
|
|
216
|
-
} else if (dir.match(/win32-ia32/)) {
|
|
217
|
-
// 32bit windows is not supported
|
|
218
|
-
keepDir = false
|
|
219
|
-
} else if (dir.match(/linux(.+)musl/)) {
|
|
220
|
-
// linux musl is not supported
|
|
221
|
-
keepDir = false
|
|
222
|
-
} else if (dir.match(/linux-arm$/) || dir.match(/linux-arm-gnueabihf/)) {
|
|
223
|
-
// linux arm (non arm64) is not supported
|
|
224
|
-
keepDir = false
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (!keepDir) {
|
|
228
|
-
console.log('Removing unneeded prebuild dir:', dir)
|
|
229
|
-
await fs.rm(path.join(prebuildDirName, dir), { recursive: true, force: true })
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Create tgz of the build
|
|
235
|
-
let tgzFile = toSanitizedDirname(`${manifestJson.id}-${manifestJson.version}`)
|
|
236
|
-
if (typeof argv['output'] === 'string') {
|
|
237
|
-
// -o flag, to allow legacy behaviour creating pkg.tgz output
|
|
238
|
-
tgzFile = argv['output']
|
|
239
|
-
}
|
|
240
|
-
tgzFile += '.tgz'
|
|
241
|
-
console.log('Writing compressed package output to', tgzFile)
|
|
242
|
-
|
|
243
|
-
await tar
|
|
244
|
-
.create(
|
|
245
|
-
{
|
|
246
|
-
gzip: true,
|
|
247
|
-
},
|
|
248
|
-
[packageBaseDir],
|
|
249
|
-
)
|
|
250
|
-
.pipe(fs.createWriteStream(tgzFile))
|
|
File without changes
|
|
File without changes
|