package-standalone.mjs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #!/usr/bin/env node
  2. import archiver from "archiver"
  3. import { execSync } from "child_process"
  4. import fs from "fs"
  5. import { cp } from "fs/promises"
  6. import { glob } from "glob"
  7. import minimatch from "minimatch"
  8. import path from "path"
  9. const BUILD_DIR = "dist-standalone"
  10. const RUNTIME_DEPS_DIR = "standalone/runtime-files"
  11. async function main() {
  12. await installNodeDependencies()
  13. await zipDistribution()
  14. }
  15. async function installNodeDependencies() {
  16. await cpr(RUNTIME_DEPS_DIR, BUILD_DIR)
  17. console.log("Running npm install in distribution directory...")
  18. const cwd = process.cwd()
  19. process.chdir(BUILD_DIR)
  20. try {
  21. execSync("npm install", { stdio: "inherit" })
  22. // Move the vscode directory into node_modules.
  23. // It can't be installed using npm because it will create a symlink which cannot be unzipped correctly on windows.
  24. fs.renameSync("vscode", path.join("node_modules", "vscode"))
  25. } catch (error) {
  26. console.error("Error during setup:", error)
  27. process.exit(1)
  28. } finally {
  29. process.chdir(cwd)
  30. }
  31. // Check for native .node modules.
  32. const nativeModules = await glob("**/*.node", { cwd: BUILD_DIR, nodir: true })
  33. if (nativeModules.length > 0) {
  34. console.error("Native node modules cannot be included in the standalone distribution:\n", nativeModules.join("\n"))
  35. process.exit(1)
  36. }
  37. }
  38. async function zipDistribution() {
  39. // Zip the build directory (excluding any pre-existing output zip).
  40. const zipPath = path.join(BUILD_DIR, "standalone.zip")
  41. const output = fs.createWriteStream(zipPath)
  42. const archive = archiver("zip", { zlib: { level: 3 } })
  43. output.on("close", () => {
  44. console.log(`Created ${zipPath} (${(archive.pointer() / 1024 / 1024).toFixed(1)} MB)`)
  45. })
  46. archive.on("warning", (err) => {
  47. console.warn(`Warning: ${err}`)
  48. })
  49. archive.on("error", (err) => {
  50. throw err
  51. })
  52. archive.pipe(output)
  53. // Add all the files from the standalone build dir.
  54. archive.glob("**/*", {
  55. cwd: BUILD_DIR,
  56. ignore: ["standalone.zip"],
  57. })
  58. // Exclude the same files as the VCE vscode extension packager.
  59. // Also ignore the dist directory, the build directory for the extension.
  60. const isIgnored = createIsIgnored(["dist/**"])
  61. // Add the whole cline directory under "extension", except the for the ignored files.
  62. archive.directory(process.cwd(), "extension", (entry) => {
  63. if (isIgnored(entry.name)) {
  64. log_verbose("Ignoring", entry.name)
  65. return false
  66. }
  67. return entry
  68. })
  69. console.log("Zipping package...")
  70. await archive.finalize()
  71. }
  72. /**
  73. * This is based on https://github.com/microsoft/vscode-vsce/blob/fafad8a63e9cf31179f918eb7a4eeb376834c904/src/package.ts#L1695
  74. * because the .vscodeignore format is not compatible with the `ignore` npm module.
  75. */
  76. function createIsIgnored(standaloneIgnores) {
  77. const MinimatchOptions = { dot: true }
  78. const defaultIgnore = [
  79. ".vscodeignore",
  80. "package-lock.json",
  81. "npm-debug.log",
  82. "yarn.lock",
  83. "yarn-error.log",
  84. "npm-shrinkwrap.json",
  85. ".editorconfig",
  86. ".npmrc",
  87. ".yarnrc",
  88. ".gitattributes",
  89. "*.todo",
  90. "tslint.yaml",
  91. ".eslintrc*",
  92. ".babelrc*",
  93. ".prettierrc*",
  94. ".cz-config.js",
  95. ".commitlintrc*",
  96. "webpack.config.js",
  97. "ISSUE_TEMPLATE.md",
  98. "CONTRIBUTING.md",
  99. "PULL_REQUEST_TEMPLATE.md",
  100. "CODE_OF_CONDUCT.md",
  101. ".github",
  102. ".travis.yml",
  103. "appveyor.yml",
  104. "**/.git",
  105. "**/.git/**",
  106. "**/*.vsix",
  107. "**/.DS_Store",
  108. "**/*.vsixmanifest",
  109. "**/.vscode-test/**",
  110. "**/.vscode-test-web/**",
  111. ]
  112. const rawIgnore = fs.readFileSync(".vscodeignore", "utf8")
  113. // Parse raw ignore by splitting output into lines and filtering out empty lines and comments
  114. const parsedIgnore = rawIgnore
  115. .split(/[\n\r]/)
  116. .map((s) => s.trim())
  117. .filter((s) => !!s)
  118. .filter((i) => !/^\s*#/.test(i))
  119. // Add '/**' to possible folder names
  120. const expandedIgnore = [
  121. ...parsedIgnore,
  122. ...parsedIgnore.filter((i) => !/(^|\/)[^/]*\*[^/]*$/.test(i)).map((i) => (/\/$/.test(i) ? `${i}**` : `${i}/**`)),
  123. ]
  124. // Combine with default ignore list
  125. // Also ignore the dist directory- the build directory for the extension.
  126. const allIgnore = [...defaultIgnore, ...expandedIgnore, ...standaloneIgnores]
  127. // Split into ignore and negate list
  128. const [ignore, negate] = allIgnore.reduce(
  129. (r, e) => (!/^\s*!/.test(e) ? [[...r[0], e], r[1]] : [r[0], [...r[1], e]]),
  130. [[], []],
  131. )
  132. function isIgnored(f) {
  133. return (
  134. ignore.some((i) => minimatch(f, i, MinimatchOptions)) &&
  135. !negate.some((i) => minimatch(f, i.substr(1), MinimatchOptions))
  136. )
  137. }
  138. return isIgnored
  139. }
  140. /* cp -r */
  141. async function cpr(source, dest) {
  142. await cp(source, dest, {
  143. recursive: true,
  144. preserveTimestamps: true,
  145. dereference: false, // preserve symlinks instead of following them
  146. })
  147. }
  148. function log_verbose(...args) {
  149. if (process.argv.includes("-v") || process.argv.includes("--verbose")) {
  150. console.log(...args)
  151. }
  152. }
  153. await main()