1
0

Taskfile.yml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. version: '3'
  2. tasks:
  3. go:mod:tidy:
  4. summary: Runs `go mod tidy`
  5. internal: true
  6. # Universal/multi-arch builds invoke this concurrently from parallel deps;
  7. # two `go mod tidy` processes racing on go.mod can corrupt it (#4637).
  8. run: once
  9. cmds:
  10. - go mod tidy
  11. install:frontend:deps:
  12. summary: Install frontend dependencies
  13. run: once
  14. cmds:
  15. - task: install:frontend:deps:{{.PACKAGE_MANAGER}}
  16. install:frontend:deps:npm:
  17. dir: frontend
  18. sources:
  19. - package.json
  20. - package-lock.json
  21. generates:
  22. - node_modules
  23. preconditions:
  24. - sh: npm version
  25. msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/"
  26. cmds:
  27. - npm install
  28. install:frontend:deps:bun:
  29. dir: frontend
  30. sources:
  31. - package.json
  32. - bun.lock
  33. - bun.lockb
  34. generates:
  35. - node_modules
  36. preconditions:
  37. - sh: bun --version
  38. msg: "bun not found"
  39. cmds:
  40. - bun install
  41. install:frontend:deps:pnpm:
  42. dir: frontend
  43. sources:
  44. - package.json
  45. - pnpm-lock.yaml
  46. generates:
  47. - node_modules
  48. preconditions:
  49. - sh: pnpm --version
  50. msg: "pnpm not found"
  51. cmds:
  52. - pnpm install
  53. install:frontend:deps:yarn:
  54. dir: frontend
  55. sources:
  56. - package.json
  57. - yarn.lock
  58. status:
  59. - test -d node_modules || test -f .pnp.cjs
  60. preconditions:
  61. - sh: yarn --version
  62. msg: "yarn not found"
  63. cmds:
  64. - yarn install
  65. build:frontend:
  66. label: build:frontend (DEV={{.DEV}} RUNNER={{.PACKAGE_MANAGER}})
  67. summary: Build the frontend project
  68. # darwin:build:universal runs its per-arch builds as parallel deps, each of
  69. # which depends on this task. Without run:once the two executions race:
  70. # one regenerates frontend/bindings (-clean deletes it first) while the
  71. # other's bundler is reading it, failing intermittently with
  72. # 'Could not resolve "./bindings/<pkg>"' (#4637).
  73. run: once
  74. dir: frontend
  75. sources:
  76. - "**/*"
  77. - exclude: node_modules/**/*
  78. generates:
  79. - dist/**/*
  80. deps:
  81. - task: install:frontend:deps
  82. - task: generate:bindings
  83. vars:
  84. BUILD_FLAGS:
  85. ref: .BUILD_FLAGS
  86. OBFUSCATED:
  87. ref: .OBFUSCATED
  88. cmds:
  89. - task: frontend:run
  90. vars:
  91. SCRIPT: '{{if eq .DEV "true"}}build:dev{{else}}build{{end}}'
  92. env:
  93. PRODUCTION: '{{if eq .DEV "true"}}false{{else}}true{{end}}'
  94. frontend:run:
  95. summary: Run a frontend script with selected runner
  96. cmds:
  97. - task: frontend:run:{{.PACKAGE_MANAGER}}
  98. vars:
  99. SCRIPT: "{{.SCRIPT}}"
  100. vars:
  101. SCRIPT: "{{.SCRIPT}}"
  102. frontend:run:npm:
  103. dir: frontend
  104. cmds:
  105. - npm run {{.SCRIPT}} -q
  106. vars:
  107. SCRIPT: "{{.SCRIPT}}"
  108. frontend:run:yarn:
  109. dir: frontend
  110. cmds:
  111. - yarn {{.SCRIPT}}
  112. vars:
  113. SCRIPT: "{{.SCRIPT}}"
  114. frontend:run:pnpm:
  115. dir: frontend
  116. cmds:
  117. - pnpm run {{.SCRIPT}}
  118. vars:
  119. SCRIPT: "{{.SCRIPT}}"
  120. frontend:run:bun:
  121. dir: frontend
  122. cmds:
  123. - bun run {{.SCRIPT}}
  124. vars:
  125. SCRIPT: "{{.SCRIPT}}"
  126. frontend:vendor:puppertino:
  127. summary: Fetches Puppertino CSS into frontend/public for consistent mobile styling
  128. sources:
  129. - frontend/public/puppertino/puppertino.css
  130. generates:
  131. - frontend/public/puppertino/puppertino.css
  132. cmds:
  133. - |
  134. set -euo pipefail
  135. mkdir -p frontend/public/puppertino
  136. # If bundled Puppertino exists, prefer it. Otherwise, try to fetch, but don't fail build on error.
  137. if [ ! -f frontend/public/puppertino/puppertino.css ]; then
  138. echo "No bundled Puppertino found. Attempting to fetch from GitHub..."
  139. if curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/dist/css/full.css -o frontend/public/puppertino/puppertino.css; then
  140. curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/LICENSE -o frontend/public/puppertino/LICENSE || true
  141. echo "Puppertino CSS downloaded to frontend/public/puppertino/puppertino.css"
  142. else
  143. echo "Warning: Could not fetch Puppertino CSS. Proceeding without download since template may bundle it."
  144. fi
  145. else
  146. echo "Using bundled Puppertino at frontend/public/puppertino/puppertino.css"
  147. fi
  148. # Ensure index.html includes Puppertino CSS and button classes
  149. INDEX_HTML=frontend/index.html
  150. if [ -f "$INDEX_HTML" ]; then
  151. if ! grep -q 'href="/puppertino/puppertino.css"' "$INDEX_HTML"; then
  152. # Insert Puppertino link tag after style.css link
  153. awk '
  154. /href="\/style.css"\/?/ && !x { print; print " <link rel=\"stylesheet\" href=\"/puppertino/puppertino.css\"/>"; x=1; next }1
  155. ' "$INDEX_HTML" > "$INDEX_HTML.tmp" && mv "$INDEX_HTML.tmp" "$INDEX_HTML"
  156. fi
  157. # Replace default .btn with Puppertino primary button classes if present
  158. sed -E -i'' 's/class=\"btn\"/class=\"p-btn p-prim-col\"/g' "$INDEX_HTML" || true
  159. fi
  160. generate:bindings:
  161. summary: Generates bindings for the frontend
  162. run: once
  163. deps:
  164. - task: go:mod:tidy
  165. sources:
  166. - "**/*.[jt]s"
  167. - exclude: frontend/**/*
  168. - frontend/bindings/**/* # Rerun when switching between dev/production mode causes changes in output
  169. - "**/*.go"
  170. - go.mod
  171. - go.sum
  172. generates:
  173. - frontend/bindings/**/*
  174. cmds:
  175. - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true{{if eq .OBFUSCATED "true"}} -obfuscated{{end}} -ts -i
  176. generate:icons:
  177. summary: Generates the Windows `.ico` and Mac `.icns` from appicon.png (drawn by `go run ./tools/icon build/appicon.png`).
  178. run: once
  179. dir: build
  180. sources:
  181. - "appicon.png"
  182. generates:
  183. - "darwin/icons.icns"
  184. - "windows/icon.ico"
  185. cmds:
  186. - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico
  187. dev:frontend:
  188. summary: Runs the frontend in development mode
  189. deps:
  190. - task: install:frontend:deps
  191. cmds:
  192. - task: frontend:dev:{{.PACKAGE_MANAGER}}
  193. frontend:dev:npm:
  194. dir: frontend
  195. cmds:
  196. - npm run dev -- --port {{.VITE_PORT}} --strictPort
  197. frontend:dev:yarn:
  198. dir: frontend
  199. cmds:
  200. - yarn dev --port {{.VITE_PORT}} --strictPort
  201. frontend:dev:pnpm:
  202. dir: frontend
  203. cmds:
  204. - pnpm dev --port {{.VITE_PORT}} --strictPort
  205. frontend:dev:bun:
  206. dir: frontend
  207. cmds:
  208. - bun run dev --port {{.VITE_PORT}} --strictPort
  209. update:build-assets:
  210. summary: Updates the build assets
  211. dir: build
  212. cmds:
  213. - wails3 update build-assets -name "{{.APP_NAME}}" -binaryname "{{.APP_NAME}}" -config config.yml -dir .
  214. build:server:
  215. summary: Builds the application in server mode (no GUI, HTTP server only)
  216. desc: |
  217. Builds a production server binary by default: -tags server,production,
  218. -trimpath and a stripped binary, mirroring the desktop `build` task.
  219. Server mode runs as a pure HTTP server without native GUI dependencies.
  220. Usage: task build:server [DEV=true] [OBFUSCATED=true] [EXTRA_TAGS=tag1,tag2]
  221. DEV=true development server (-tags server, no strip, inlining kept)
  222. OBFUSCATED=true obfuscated build via garble (requires garble installed)
  223. EXTRA_TAGS additional comma-separated build tags
  224. deps:
  225. - task: build:frontend
  226. vars:
  227. DEV:
  228. ref: .DEV
  229. BUILD_FLAGS:
  230. ref: .BUILD_FLAGS
  231. OBFUSCATED:
  232. ref: .OBFUSCATED
  233. preconditions:
  234. - sh: '{{if eq .OBFUSCATED "true"}}command -v garble >/dev/null 2>&1{{else}}true{{end}}'
  235. msg: "garble is required for obfuscated builds. Install it with: go install mvdan.cc/garble@v0.16.0 (requires Go 1.24+). See https://github.com/burrowers/garble/releases for version/toolchain compatibility."
  236. cmds:
  237. - '{{if eq .OBFUSCATED "true"}}garble {{.GARBLE_ARGS}} build{{else}}go build{{end}} {{.BUILD_FLAGS}} -o "{{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}}"'
  238. vars:
  239. BUILD_FLAGS: '-tags server{{if eq .DEV "true"}}{{if eq .OBFUSCATED "true"}},wails_obfuscated{{end}}{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -buildvcs=false -gcflags=all="-l"{{else}},production{{if eq .OBFUSCATED "true"}},wails_obfuscated{{end}}{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s"{{end}}'
  240. run:server:
  241. summary: Builds and runs a development server (DEV=true)
  242. deps:
  243. - task: build:server
  244. vars:
  245. DEV: "true"
  246. cmds:
  247. - '"./{{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}}"'
  248. build:docker:
  249. summary: Builds a Docker image for server mode deployment
  250. desc: |
  251. Creates a minimal Docker image containing the production server binary.
  252. Defaults to a pure-Go static binary on a distroless/static base. The
  253. production frontend is built first so the embedded assets are current.
  254. Usage: task build:docker [TAG=myapp:latest] [CGO_ENABLED=1] [GO_IMAGE=...] [RUNTIME_IMAGE=...]
  255. For CGO apps, set CGO_ENABLED=1 with libc-compatible builder/runtime images, e.g.:
  256. task build:docker CGO_ENABLED=1 GO_IMAGE=golang:bookworm RUNTIME_IMAGE=gcr.io/distroless/base-debian12
  257. deps:
  258. # Build the production frontend so frontend/dist (embedded by the Go build
  259. # inside the image) is present and current in the Docker build context.
  260. # Pass the server,production tags so binding generation analyses the same
  261. # build the Docker image compiles, not the default-tag build.
  262. - task: build:frontend
  263. vars:
  264. BUILD_FLAGS: "-tags server,production"
  265. cmds:
  266. - >-
  267. docker build
  268. --build-arg CGO_ENABLED={{.CGO_ENABLED | default "0"}}
  269. --build-arg GO_IMAGE={{.GO_IMAGE | default "golang:alpine"}}
  270. --build-arg RUNTIME_IMAGE={{.RUNTIME_IMAGE | default "gcr.io/distroless/static-debian12"}}
  271. -t {{.TAG | default (printf "%s:latest" .APP_NAME)}}
  272. -f build/docker/Dockerfile.server .
  273. vars:
  274. TAG: "{{.TAG}}"
  275. preconditions:
  276. - sh: docker info > /dev/null 2>&1
  277. msg: "Docker is required. Please install Docker first."
  278. - sh: test -f build/docker/Dockerfile.server
  279. msg: "Dockerfile.server not found. Run 'wails3 update build-assets' to generate it."
  280. run:docker:
  281. summary: Builds and runs the Docker image
  282. desc: |
  283. Builds the Docker image and runs it, exposing port 8080.
  284. Usage: task run:docker [TAG=myapp:latest] [PORT=8080]
  285. Note: The internal container port is always 8080. The PORT variable
  286. only changes the host port mapping. Ensure your app uses port 8080
  287. or modify the Dockerfile to match your ServerOptions.Port setting.
  288. deps:
  289. - task: build:docker
  290. vars:
  291. TAG:
  292. ref: .TAG
  293. cmds:
  294. - docker run --rm -p {{.PORT | default "8080"}}:8080 {{.TAG | default (printf "%s:latest" .APP_NAME)}}
  295. vars:
  296. TAG: "{{.TAG}}"
  297. PORT: "{{.PORT}}"
  298. setup:docker:
  299. summary: Builds Docker image for cross-compilation (~800MB download)
  300. desc: |
  301. Builds the Docker image needed for cross-compiling to any platform.
  302. Run this once to enable cross-platform builds from any OS.
  303. cmds:
  304. - docker build -t wails-cross -f build/docker/Dockerfile.cross build/docker/
  305. preconditions:
  306. - sh: docker info > /dev/null 2>&1
  307. msg: "Docker is required. Please install Docker first."
  308. ios:device:list:
  309. summary: Lists connected iOS devices (UDIDs)
  310. cmds:
  311. - xcrun xcdevice list
  312. ios:run:device:
  313. summary: Build, install, and launch on a physical iPhone using Apple tools (xcodebuild/devicectl)
  314. vars:
  315. PROJECT: '{{.PROJECT}}' # e.g., build/ios/xcode/<YourProject>.xcodeproj
  316. SCHEME: '{{.SCHEME}}' # e.g., ios.dev
  317. CONFIG: '{{.CONFIG | default "Debug"}}'
  318. DERIVED: '{{.DERIVED | default "build/ios/DerivedData"}}'
  319. UDID: '{{.UDID}}' # from `task ios:device:list`
  320. BUNDLE_ID: '{{.BUNDLE_ID}}' # e.g., com.yourco.wails.ios.dev
  321. TEAM_ID: '{{.TEAM_ID}}' # optional, if your project is not already set up for signing
  322. preconditions:
  323. - sh: xcrun -f xcodebuild
  324. msg: "xcodebuild not found. Please install Xcode."
  325. - sh: xcrun -f devicectl
  326. msg: "devicectl not found. Please update to Xcode 15+ (which includes devicectl)."
  327. - sh: test -n '{{.PROJECT}}'
  328. msg: "Set PROJECT to your .xcodeproj path (e.g., PROJECT=build/ios/xcode/App.xcodeproj)."
  329. - sh: test -n '{{.SCHEME}}'
  330. msg: "Set SCHEME to your app scheme (e.g., SCHEME=ios.dev)."
  331. - sh: test -n '{{.UDID}}'
  332. msg: "Set UDID to your device UDID (see: task ios:device:list)."
  333. - sh: test -n '{{.BUNDLE_ID}}'
  334. msg: "Set BUNDLE_ID to your app's bundle identifier (e.g., com.yourco.wails.ios.dev)."
  335. cmds:
  336. - |
  337. set -euo pipefail
  338. echo "Building for device: UDID={{.UDID}} SCHEME={{.SCHEME}} PROJECT={{.PROJECT}}"
  339. XCB_ARGS=(
  340. -project "{{.PROJECT}}"
  341. -scheme "{{.SCHEME}}"
  342. -configuration "{{.CONFIG}}"
  343. -destination "id={{.UDID}}"
  344. -derivedDataPath "{{.DERIVED}}"
  345. -allowProvisioningUpdates
  346. -allowProvisioningDeviceRegistration
  347. )
  348. # Optionally inject signing identifiers if provided
  349. if [ -n '{{.TEAM_ID}}' ]; then XCB_ARGS+=(DEVELOPMENT_TEAM={{.TEAM_ID}}); fi
  350. if [ -n '{{.BUNDLE_ID}}' ]; then XCB_ARGS+=(PRODUCT_BUNDLE_IDENTIFIER={{.BUNDLE_ID}}); fi
  351. xcodebuild "${XCB_ARGS[@]}" build | xcpretty || true
  352. # If xcpretty isn't installed, run without it
  353. if [ "${PIPESTATUS[0]}" -ne 0 ]; then
  354. xcodebuild "${XCB_ARGS[@]}" build
  355. fi
  356. # Find built .app
  357. APP_PATH=$(find "{{.DERIVED}}/Build/Products" -type d -name "*.app" -maxdepth 3 | head -n 1)
  358. if [ -z "$APP_PATH" ]; then
  359. echo "Could not locate built .app under {{.DERIVED}}/Build/Products" >&2
  360. exit 1
  361. fi
  362. echo "Installing: $APP_PATH"
  363. xcrun devicectl device install app --device "{{.UDID}}" "$APP_PATH"
  364. echo "Launching: {{.BUNDLE_ID}}"
  365. xcrun devicectl device process launch --device "{{.UDID}}" --stderr console --stdout console "{{.BUNDLE_ID}}"