devkit English

Sites

Một site là một thư mục Laravel: có file artisan ở thư mục gốc. devkit cấp cho nó một database trên stack của bạn, một .env trỏ vào stack đó, một web server, các process chạy nền và một bộ thao tác chỉ cần một cú bấm. Trang này nói về tất cả những thứ đó.

Thêm site: park và link

Park một thư mục chứa các dự án của bạn. Mọi thư mục con có file artisan là một site, mang tên thư mục của nó, và dự án bạn thêm vào đó sau này cũng tự xuất hiện.

devkit park ~/Project/sites
devkit site list
SITE              ENGINE   PHP  DB                BRANCH  URL                    STATE
core-development  artisan  8.3  core_development  main    http://localhost:8100  running
shop              artisan  8.4  shop              main*                          stopped

Link một thư mục nằm ở chỗ khác. --name đặt cho nó một tên khác với tên thư mục.

devkit link ~/work/legacy-crm --name crm

Trong app, Sites → Park thư mục… và Liên kết thư mục… mở hộp chọn thư mục. Site được park hiện theo từng thư mục, site được liên kết nằm trong nhóm riêng.

Tên của site (slug) là tên thư mục, còn database là tên đó với dấu chấm và gạch ngang đổi thành gạch dưới: core-development có core_development, webpress.vn có webpress_vn. Đổi bằng devkit site set <site> --db <name>.

Bỏ park và bỏ link. devkit 1.0 chưa có lệnh để quên một thư mục park, một thư mục liên kết hay một stack. Muốn cất một site đi, hãy ẩn nó: site dừng, rời khỏi danh sách và giữ nguyên mọi thứ. Site được park có thư mục bị xoá bên ngoài devkit sẽ tự biến mất khỏi danh sách; site liên kết thì vẫn được liệt kê cho tới khi bạn chạy devkit site delete <site> --yes, lúc đó devkit chỉ quên nó.

Danh sách site

devkit site list hiện mọi site với engine, phiên bản PHP, database, branch git, URL và trạng thái thực tế. Lane nằm dưới site của nó. Trong cột branch, * nghĩa là có thay đổi chưa commit, còn ↑2 / ↓3 là số commit đi trước / đi sau upstream (tính tới lần fetch gần nhất). --all hiện cả site đã ẩn. App hiện cùng bảng này, kèm badge doctor trên mỗi dòng.

Clone từ git

devkit site clone tạo site mới từ một repository trong một lần: nó clone vào một thư mục park, rồi chạy các bước thiết lập.

devkit site clone git@github.com:acme/shop.git --php 8.3 --start --progress
… git clone into ~/Project/sites/shop
… setup step submodules
… setup step composer
… setup step pnpm
… setup step env
… setup step up
shop at ~/Project/sites/shop
  clone      done    git@github.com:acme/shop.git (…)
  submodules done    …
  composer   done    …
  pnpm       done    …
  env        done    …
  up         done    up at http://localhost:8102
shop is up at http://localhost:8102

Các bước, theo thứ tự, bước nào cũng bỏ qua được:

BướcLàm gìBỏ qua bằng
submodulesgit submodule update --init --recursive, rồi đưa từng submodule lên branch ghi trong .gitmodules thay vì một commit detached, khi branch đó chứa commit đã ghi nhận (nếu không, submodule vẫn detached và devkit cảnh báo)--no-submodules
composercomposer install với PHP của site (--php)--no-composer
pnpmpnpm install, khi có package.json--no-pnpm
envlưu một template .env tạo từ .env.example (APP_KEY trống sẽ được cấp key mới) và tạo database--no-env
upsite up ở cuốichỉ chạy khi có --start
  • --into <dir> chọn thư mục park; bỏ trống được khi bạn chỉ có một. --name đặt tên thư mục và tên site (mặc định: lấy từ URL), --branch chọn branch để clone (mặc định: branch mặc định của remote).
  • URL có thể là https://…, git@host:org/repo.git hoặc một repository trên máy. devkit dùng thông tin đăng nhập git của chính bạn (SSH agent hoặc credential helper) và không bao giờ hỏi hay lưu mật khẩu, nên repository riêng tư cần bạn thiết lập quyền truy cập từ trước.
  • Nếu bản thân bước clone thất bại, không có gì bị để lại. Nếu một bước sau đó thất bại, bản clone vẫn còn và devkit nêu tên bước đó. Sửa nguyên nhân, rồi chạy lại các bước còn lại bằng devkit site setup <site>, lệnh này nhận cùng các flag --no-… và --start. Bước nào chạy lại cũng an toàn.
  • site setup cũng dùng được cho dự án bạn tự sao chép hay tự clone.
  • Thêm --progress để xem từng bước khi nó diễn ra (app luôn hiện các bước).

Trong app: Clone từ git… (cạnh mỗi thư mục park trong Sites) hỏi URL repository, Tên thư mục, Branch và, khi bạn park nhiều thư mục, nơi để clone vào. Trong Sau khi clone, mọi bước đều bật trừ Chạy site khi đã sẵn sàng, và phiên bản PHP cho composer có ô chọn. Sau đó sheet hiện từng bước khi nó chạy.

Engine: artisan hay caddy

Engine là cách một site được phục vụ. Mỗi site có một engine; site nào không đặt thì theo engine mặc định trong Cài đặt (artisan nếu bạn không đổi).

artisan (mặc định)caddy
Web serverphp artisan serve trên máycontainer Caddy của stack
PHPmột file chạy trên máy (Homebrew, distro, phpenv…)một container PHP-FPM đúng phiên bản đó trong một stack của bạn
URLhttp://localhost:<port>, mỗi site một porthttps://<site>.localhost với chứng chỉ được tin cậy
CầnPHP trên máymột stack có service caddy và php, mkcert, chạy devkit trust một lần
Xdebugtheo từng site hoặc lanetheo từng container PHP, tức là cho mọi site dùng nó
Hợp vớiphần lớn công việc hằng ngày: chạy nhanh, không cần thiết lập gìtính năng chỉ chạy với HTTPS, routing giống production, extension PHP bạn không muốn cài trên máy

Chọn artisan, trừ khi có thứ cần HTTPS hoặc một tên host thật: callback OAuth và thanh toán đòi https://, cookie Secure hoặc SameSite=None, service worker, hoặc routing theo subdomain. Khi đó hãy dùng caddy. Cách thiết lập nằm ở Stack, PHP và HTTPS.

devkit site set shop --engine caddy --php 8.3
devkit site up shop          # https://shop.localhost

Đổi engine của một site đang chạy sẽ dừng site và các lane của nó với engine cũ trước; site up chạy chúng với engine mới. Trong app: menu … của site → Đổi engine…, mục này cho biết những gì sẽ thay đổi trước khi bạn chuyển.

Phiên bản PHP cho từng site

devkit site set shop --php 8.2     # site này chạy PHP 8.2
devkit site set shop --php ""      # quay về PHP mặc định
devkit php check 8.4 shop          # chạy được trên 8.4 không? (composer check-platform-reqs)
  • Site không có phiên bản riêng thì dùng PHP mặc định (Cài đặt), và mặc định trống nghĩa là lệnh php trong PATH.
  • Lane luôn chạy phiên bản của site.
  • Phiên bản đó phải được cài sẵn. Thiếu thì lỗi PHP_VERSION_MISSING kèm lệnh cài (brew install php@8.2 trên macOS, package của distro trên Linux).
  • Site đang chạy giữ file chạy hiện tại cho tới lần chạy kế tiếp; khi đó site up chạy lại server và các process có lệnh thay đổi.
  • Với engine caddy, cùng lựa chọn này sẽ chọn container PHP đúng phiên bản đó.

Trong app, cột PHP của bảng Sites và thẻ PHP trong chi tiết site là các ô chọn. Sau khi đổi từ chi tiết site, một banner báo Đã chuyển sang PHP 8.2, kèm Hoàn tác và, khi site vẫn đang chạy file chạy cũ, Chạy lại ngay.

Port và URL

  • Site artisan nhận port từ dải trong Cài đặt, mặc định 8100–8999. Một bộ cấp phát duy nhất cấp mọi port cho mọi site, lane và process Vite, và kiểm tra port còn trống.
  • Site giữ port của nó qua các lần chạy lại, kể cả khi sau này bạn đổi dải port.
  • Site caddy được phục vụ ở https://<site>.<suffix> và lane ở https://<lane>.<site>.<suffix>. Suffix là localhost nếu bạn không đổi. Khi port HTTPS của Caddy được publish ở port khác 443 (ví dụ 8443), URL có kèm port đó.
  • Khi port của một site đã dừng bị chương trình khác chiếm, devkit status và app báo PORT_IN_USE.

Template .env

Mọi site đều có một template .env. Mỗi lần site up, devkit render nó thành .env của site, nên site luôn trỏ đúng port thật của stack và đúng database. Lane render template của site với database, port và URL của riêng nó.

  • Template khởi tạo. Cho tới khi bạn lưu một template, template là .env hiện tại của bạn (hoặc .env.example) với các giá trị sau được thay bằng biến: APP_URL, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD, REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, MAIL_HOST, MAIL_PORT (mỗi biến chỉ khi stack có service tương ứng). Mọi dòng khác giữ nguyên.
  • Sao lưu. .env đầu tiên của bạn được giữ một lần ở ~/.config/devkit/backups/<site>/env.orig, và file trước mỗi lần ghi ở env.prev. Không ghi gì khi nội dung không đổi. Bản sao lưu không bao giờ nằm trong thư mục site.
  • Lỗi. Một biến không xác định, hoặc biến có service mà stack không có, sẽ lỗi TEMPLATE_VAR_UNRESOLVED kèm tên biến, và .env hiện có được để nguyên.
devkit template get shop > shop.env.tpl     # template đã lưu, hoặc template khởi tạo
$EDITOR shop.env.tpl
devkit template render shop --file shop.env.tpl   # .env nó sẽ ghi lúc này; không ghi gì
devkit template set shop --file shop.env.tpl

Trong app: Templates → Sửa… (hoặc Sửa template .env… trong menu … của site) hiện template, .env nó render ra ngay lúc này (mật khẩu bị ẩn cho tới khi bạn bấm hiện) và mọi biến cùng giá trị. Lưu sẽ lưu template; Lưu và chạy lại site còn chạy lại site và các lane đang chạy của nó với template mới.

Biến

BiếnGiá trị
{{site.url}}artisan: http://localhost:<port>; caddy: https://<host>
{{site.host}}, {{site.port}}tên host và port (caddy: port HTTPS của Caddy)
{{site.slug}}, {{site.path}}tên và thư mục của site (hoặc lane)
{{lane.name}}, {{lane.index}}, {{lane.suffix}}tên lane, số thứ tự và _l<index>; cả ba đều trống với chính site
{{db.name}}database của site, hoặc bản fork của lane
{{mysql.host}}, {{mysql.port}}, {{mysql.user}}, {{mysql.password}}MySQL hoặc MariaDB của stack, với quyền root (lane cần tạo database)
{{redis.host}}, {{redis.port}}, {{redis.password}}Redis của stack
{{mail.host}}, {{mail.port}}, {{mail.ui}}Mailpit hoặc MailHog của stack: SMTP, và URL hộp thư để mở trong trình duyệt
{{s3.endpoint}}, {{s3.key}}, {{s3.secret}}, {{s3.bucket}}MinIO, LocalStack hoặc Garage của stack. Key là MINIO_ROOT_USER / MINIO_ROOT_PASSWORD của MinIO, test / test của LocalStack, và trống với Garage (tạo key bằng CLI riêng của nó). Bucket là tên database của site
{{env.NAME}}biến NAME trong môi trường của chính devkit

Với engine artisan, service được gọi theo địa chỉ publish trên máy bạn (127.0.0.1 và port trên máy). Với engine caddy, PHP chạy trong container, nên service được gọi theo tên service và port của container (database:3306, redis:6379).

Các lane dùng chung Redis. Hãy đặt prefix riêng theo từng lane cho key cache, session và queue, nếu không lane sẽ đọc cache của site và lấy mất job queue của site:
CACHE_PREFIX=webpress{{lane.suffix}}_
REDIS_PREFIX=webpress{{lane.suffix}}_
lane new cảnh báo khi template không dùng biến {{lane.*}} nào.

Thao tác nhanh

Các việc bảo trì một cú bấm cho site hoặc lane, chạy trong thư mục của nó với PHP của nó:

Thao tácNhãnChạy
clear-logClear loglàm trống storage/logs/laravel.log (không cần PHP)
clear-cacheClear cachephp artisan optimize:clear
publish-corePublish core assetsphp artisan vendor:publish --provider="Webpress\Core\Providers\WebpressCoreProvider" --force
devkit site actions shop
devkit site action shop clear-cache
devkit site action-set shop migrate-fresh --command "php artisan migrate:fresh --seed" --label "Fresh database"
devkit site action-rm shop migrate-fresh
  • action-set thêm thao tác của riêng bạn hoặc ghi đè một thao tác mặc định; php trong lệnh nghĩa là PHP của site. action-rm xoá một thao tác đã thêm, hoặc khôi phục thao tác mặc định bạn đã ghi đè. Ba thao tác mặc định không xoá được.
  • Exit code khác 0 là lỗi ACTION_FAILED kèm những dòng output cuối.
  • Trong app, các thao tác là nút ở phần đầu chi tiết site và là mục trong menu … của site, mỗi mục có lệnh của nó làm gợi ý.

Process

Ngoài web server, site có các process chạy lâu, chạy và dừng cùng site. Cho tới khi bạn thay đổi gì đó, devkit tự nhận ra chúng từ thư mục:

ProcessLệnhChạy cùng site
queuephp artisan queue:work --tries=1có
schedulephp artisan schedule:workkhông
vite, vite:<name>mỗi vite.config.js / vite.config.<name>.js (cả .mjs, .ts) ở thư mục gốc một process: pnpm vite --config <file> --port {port} --strictPort (yarn hoặc npx --no-install tuỳ lockfile)không
devkit proc list shop
PROCESS   STATUS   PORT  AUTOSTART  COMMAND
queue     running        true       php artisan queue:work --tries=1
schedule  stopped        false      php artisan schedule:work
vite      running  8104  false      pnpm vite --config vite.config.js --port {port} --strictPort

devkit proc start shop schedule vite      # không ghi tên: các process autostart
devkit proc restart shop queue            # ví dụ sau khi sửa một class job
devkit proc stop shop                     # không ghi tên: mọi process đang chạy
devkit proc logs shop queue --lines 50

Process của riêng bạn

devkit proc add shop horizon --command "php artisan horizon" --autostart
devkit proc add shop reverb --command "php artisan reverb:start --port={port}" --port
devkit proc set shop schedule --autostart=true
devkit proc set shop vite --port=false
devkit proc rm shop reverb          # một process đã dừng
devkit proc reset shop              # bỏ các thay đổi của bạn, nhận lại các process mặc định
  • --port cấp cho process một port từ cùng bộ cấp phát; {port} trong lệnh được thay bằng port đó và biến PORT được đặt. Port vẫn được giữ khi process dừng, nên hai lane có thể chạy Vite cùng lúc.
  • Lệnh chạy không qua shell. Dấu nháy hoạt động như trong shell, nhưng pipe, &&, chuyển hướng và $VAR bị từ chối: hãy bọc chúng trong sh -c '…'.
  • Lệnh bắt đầu bằng php chạy với PHP của site (trong container của nó khi dùng caddy); mọi lệnh khác chạy trên máy.
  • Trạng thái là running, stopped hoặc exited (process bị crash: những dòng cuối của log được hiện ra). devkit không tự chạy lại process bị crash. Process thoát trong vòng một giây sẽ lỗi PROC_FAILED.
  • Lần proc add, set hoặc rm đầu tiên lưu toàn bộ danh sách của site đó; từ đó một vite.config.* mới không còn được nhận ra cho tới khi proc reset.
  • Mỗi lần chạy, devkit ghi thêm một dòng --- devkit: start vào log ở ~/.config/devkit/logs/<site>.<process>.log, tiếp theo là output của process.

Trong app, tab Processes của chi tiết site liệt kê serve và mọi process với nút chạy, dừng và chạy lại, công tắc Tự chạy, port được cấp và log của nó ở bên dưới.

exec và logs

devkit exec shop -- php artisan tinker
devkit exec shop -- composer require spatie/laravel-backup
devkit exec shop --timeout 30m -- php artisan import:catalog
devkit exec shop --xdebug -- php vendor/bin/phpunit --filter CheckoutTest

exec chạy một lệnh trong thư mục của site, với PHP của site đứng đầu PATH, nên composer và các script cũng dùng đúng phiên bản. Với caddy, lệnh php chạy trong container PHP ở cùng đường dẫn. Output hiện thẳng ra terminal và exit code là của chính lệnh đó (124 khi bị --timeout dừng, mặc định 10 phút). --xdebug chạy riêng lệnh này với Xdebug mà không đổi cài đặt của site.

devkit logs shop                          # storage/logs/laravel.log
devkit logs shop --source serve           # web server (caddy: log của container Caddy)
devkit logs shop --source proc:queue
devkit logs shop --source container:mysql --lines 50

Trong app: Xem log trong menu … của site, mỗi nguồn một tab (laravel.log, serve, từng process, từng container), có Lọc dòng, Theo dõi và Sao chép các dòng đang hiện. Tab Processes cũng hiện log của process đang chọn bên dưới bảng.

Git: branch, fetch, pull, push

Mọi site và lane hiện branch của repository riêng của nó. Thanh branch trong chi tiết site có ô chọn branch (kèm Branch mới…), Fetch, Pull, Push và Gồm cả submodule (bật sẵn).

devkit git status shop
devkit git checkout shop feat/cart             # branch local, hoặc branch mới theo dõi origin/feat/cart
devkit git checkout shop feat/new-idea --create  # branch mới tại HEAD
devkit git fetch shop
devkit git pull shop                           # --ff-only
devkit git push shop                           # submodule trước, rồi tới site
  • Checkout từ chối với DIRTY_WORKTREE, liệt kê mọi lý do, khi site (hoặc một submodule) có thay đổi chưa commit, kể cả file chưa track. Hãy commit hoặc stash trước. devkit không bao giờ tự fetch: branch không có là NOT_FOUND kèm gợi ý fetch.
  • Với submodule, checkout đưa từng submodule về commit mà branch ghi lại và đặt nó lên branch của nó. Server và các process PHP của site đang chạy sẽ chạy lại. composer.lock hoặc pnpm-lock.yaml thay đổi sẽ được chỉ ra, kèm lệnh cài cần chạy.
  • Pull từ chối HEAD detached, repository có thay đổi chưa commit và branch không có upstream. Push đặt upstream ở lần push đầu tiên. Nếu push một submodule thất bại, site không được push.
  • Thêm --with-submodules=false để bỏ qua các submodule.

Modules và Extensions (submodule)

Submodule được nhóm theo thư mục cấp cao nhất: mặc định là Modules (modules/*) và Extensions (extensions/*), mỗi nhóm một tab trong chi tiết site. Mỗi dòng hiện branch của submodule (hoặc detached), branch mà .gitmodules theo dõi, các thay đổi, số commit đi trước/đi sau, cùng Pull, Push và Terminal. Mỗi tab có Checkout trong mọi, Pull tất cả và Push tất cả, còn Extensions có thêm Thêm extension….

devkit modules core-development --fetch
GROUP    PATH               BRANCH          TRACKS          HEAD     SYNC    DIRTY
modules  modules/common     release/v12.45  release/v12.45  3f2a9c1  ↑0 ↓2   -
modules  modules/framework  feat/cms        release/v12.45  8b41d0e  ↑1 ↓0   3
…

devkit modules checkout core-development feat/cms             # trong mọi submodule
devkit modules checkout core-development feat/cms --only common,framework
devkit modules checkout core-development feat/cms --create --group extensions
devkit modules pull core-development
devkit modules push core-development --group modules
devkit modules add core-development git@github.com:acme/payments.git --branch main
  • --group giới hạn lệnh trong một nhóm, --only trong một số submodule (đường dẫn, tên hoặc thư mục, cách nhau bằng dấu phẩy).
  • Submodule có thay đổi chưa commit bị bỏ qua với MODULE_DIRTY và không bao giờ bị động tới.
  • Lệnh hàng loạt báo kết quả theo từng repository: done, unchanged, skipped hoặc failed. Trong terminal, lệnh thoát với mã 1 khi có repository bị bỏ qua hoặc thất bại.
  • modules add chạy git submodule add vào extensions/<name> (hoặc theo --group, --name, --path), ghi branch vào .gitmodules và stage thay đổi. Bạn tự commit.
  • Thư mục khác: devkit site set core-development --submodule-groups modules,extensions,packages=libs (đường dẫn không kèm tên thì tên chính là đường dẫn); --submodule-groups "" khôi phục hai nhóm mặc định.

Cài đặt của site

devkit site set shop --php 8.3 --engine artisan --db shop_dev --stack local-stack
devkit site set shop --copy-files storage/app/public,.env.testing
  • --stack: database và Redis của stack nào mà site dùng (mặc định: stack bạn thêm đầu tiên).
  • --db: tên database; hai site không thể dùng chung một database.
  • --copy-files: các file và thư mục bị gitignore mà lane mới sao chép ngoài vendor/ và node_modules/ ("" xoá danh sách).

Tab Cài đặt của chi tiết site có cùng các lựa chọn này.

Ẩn và hiện lại

devkit site hide legacy-crm
devkit site unhide legacy-crm

Ẩn sẽ dừng site và các lane của nó (gỡ route của site caddy) và loại nó khỏi site list và doctor. File, database và template vẫn còn. Site đã ẩn không chạy được cho tới khi bạn hiện lại. Trong app: Ẩn khỏi devkit trong menu … của site; site đã ẩn được liệt kê ở Cài đặt → Site đã ẩn với nút Hiện lại.

Xoá

devkit site delete shop                     # không có --yes: cho biết những gì sẽ mất, không đổi gì
devkit site delete shop --trash --yes       # chuyển thư mục vào Thùng rác
devkit site delete shop --trash --drop-db --yes

Xoá sẽ gỡ các lane của site (như lane rm), dừng site, gỡ route Caddy và chứng chỉ, bản ghi của site, bản sao lưu .env và log, cùng thư mục của nó:

  • --trash chuyển thư mục vào Thùng rác (~/.Trash trên macOS, ~/.local/share/Trash trên Linux) thay vì xoá hẳn. Thùng rác phải nằm trên cùng ổ đĩa; devkit kiểm tra trước khi thay đổi gì. Trên macOS không có Put Back: bạn tự kéo thư mục trở lại.
  • --drop-db xoá cả database và snapshot của site và các lane. Không có flag này thì chúng vẫn nằm trên server.
  • devkit từ chối với DIRTY_WORKTREE khi site, một submodule hoặc một lane có thay đổi chưa commit (tính cả file untracked), commit chưa có trên remote nào (trên một branch hoặc trên HEAD detached) hoặc stash, và với thư mục không phải repository git (file của nó không có ở đâu khác). --force vẫn xoá.
  • devkit không bao giờ xoá thư mục home của bạn hay thư mục chứa một thư mục park, một stack hoặc một site khác.

Trong app, Xoá site… trước tiên hỏi devkit những gì sẽ mất và hiện ra, bắt bạn gõ tên site, cho chọn Chuyển thư mục vào Thùng rác thay vì xoá vĩnh viễn (bật sẵn) và cả database, rồi hỏi lại devkit ngay trước khi làm. Nếu có gì thay đổi trong lúc đó, không có gì bị xoá.