Skip to content

0) Tóm tắt

  • Clientlib = cơ chế bundle CSS/JS theo category.
  • Include trong page bằng category string (không link file lẻ).
  • Trục debug:
    • category name đúng?
    • allowProxy đúng?
    • css.txt/js.txt đúng order + đúng path?
    • dependencies/embed đúng?

1) Cách clientlibs hoạt động

Clientlib làm được:

  • Group file theo category
  • Khai báo dependencies (đảm bảo load order)
  • embed (gộp vào 1 request)
  • Serve qua proxy /etc.clientlibs/ (quan trọng cho Cloud; on-prem cũng nên bật để tương thích)

2) Cấu trúc clientlib chuẩn

text
/apps/<site>/clientlibs/
└── clientlib-base/
    ├── .content.xml          # cq:ClientLibraryFolder
    ├── css.txt               # order include CSS
    ├── js.txt                # order include JS
    ├── css/
    │   ├── reset.css
    │   ├── variables.css
    │   └── base.css
    └── js/
        ├── utils.js
        └── main.js

2.1 .content.xml (quan trọng)

xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0"
          xmlns:jcr="http://www.jcp.org/jcr/1.0"
          jcr:primaryType="cq:ClientLibraryFolder"
          categories="[<site>.base]"
          allowProxy="{Boolean}true"/>
PropertyÝ nghĩaNotes
categoriestên category (có thể nhiều)include bằng HTL theo string
allowProxyphục vụ qua /etc.clientlibs/nên bật để tương thích AEMaaCS
dependenciescategory phải load trướctạo thêm request
embedinline category khác vào bundle nàygiảm request

3) css.txtjs.txt (order + base)

css.txt:

text
#base=css
reset.css
variables.css
base.css

js.txt:

text
#base=js
utils.js
main.js

Rules:

  • File được concat theo đúng thứ tự liệt kê
  • #base= = prefix folder
  • Không khai báo file ⇒ không được bundle

4) Include clientlibs trong Page Component (HTL)

Template include chuẩn:

html
<sly data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
  <!-- CSS in <head> -->
  <sly data-sly-call="${clientlib.css @ categories='<site>.base'}"/>

  <!-- JS before </body> -->
  <sly data-sly-call="${clientlib.js @ categories='<site>.base'}"/>

  <!-- Both -->
  <sly data-sly-call="${clientlib.all @ categories='<site>.base'}"/>
</sly>

Multiple categories:

html
<sly data-sly-call="${clientlib.css @ categories=['<site>.base', '<site>.components']}"/>

5) Dependencies vs Embed (quy tắc chọn)

5.1 Dependencies (load order, nhiều request)

xml
<jcr:root
  jcr:primaryType="cq:ClientLibraryFolder"
  categories="[<site>.components]"
  dependencies="[<site>.base]"
  allowProxy="{Boolean}true"/>

Kết quả:

  • Request 1: <site>.base
  • Request 2: <site>.components (sau base)

5.2 Embed (gộp 1 request)

xml
<jcr:root
  jcr:primaryType="cq:ClientLibraryFolder"
  categories="[<site>.site]"
  embed="[<site>.base,<site>.components]"
  allowProxy="{Boolean}true"/>

Kết quả:

  • 1 request: <site>.site (chứa cả base + components)

Heuristic:

StrategyKhi dùng
dependencieslib dùng chung, cần cache riêng, hoặc cần đảm bảo order rõ ràng
embedbundle “site” cuối cùng để giảm request (project assets)

6) Proxy serving /etc.clientlibs/

Trạng tháiPath
không proxy/apps/<site>/clientlibs/... (thường bị chặn ngoài production)
có proxy/etc.clientlibs/<site>/clientlibs/...

Checklist:

  • [ ] allowProxy="{Boolean}true" ở mọi clientlib bạn muốn serve qua proxy
  • [ ] Include bằng HTL template (AEM tự resolve sang /etc.clientlibs/)

7) Component-specific clientlibs

Pattern:

text
/apps/<site>/components/hero/
├── .content.xml
├── hero.html
├── _cq_dialog/.content.xml
└── clientlibs/
    ├── .content.xml
    ├── css.txt
    ├── js.txt
    ├── css/hero.css
    └── js/hero.js

.content.xml của component clientlib:

xml
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0"
          jcr:primaryType="cq:ClientLibraryFolder"
          categories="[<site>.components]"
          allowProxy="{Boolean}true"/>

Note:

  • Nhiều component clientlibs có thể dùng chung 1 category (<site>.components) ⇒ bundle cùng nhau.

8) ui.frontend module (tooling hiện đại)

Mục tiêu:

  • SCSS/TS/build tool (webpack/Vite) trong ui.frontend/
  • Output assets copy sang ui.apps/.../clientlibs/...
  • Maven build/deploy package mang clientlibs vào AEM

Flow:

  1. Build frontend (npm/pnpm run build) trong ui.frontend/
  2. Copy output sang:
    • ui.apps/src/main/content/jcr_root/apps/<site>/clientlibs/...
  3. Deploy package (Maven)

Dev loop (tuỳ project):

  • aem-clientlib-generator (archetype hay dùng)
  • aemsync (sync file vào AEM khi dev)

9) Naming convention (gợi ý)

CategoryNội dungLoad
<site>.basereset/fonts/variables/globalevery page
<site>.componentsCSS/JS theo componentevery page
<site>.siteembed base + componentsevery page (single include)
<site>.dependencieslibs bên thứ badependency của site

10) Debug clientlibs (đúng thứ cần nhớ)

10.1 Xem clientlibs đang load

  • Thêm ?debugClientLibs=true vào URL page.

10.2 Rebuild/invalidate clientlibs cache (khi đổi không thấy)

  • http://localhost:4502/libs/granite/ui/content/dumplibs.rebuild.html
    • Invalidate Caches
    • Rebuild Libraries

10.3 Check trực tiếp file proxy

text
http://localhost:4502/etc.clientlibs/<site>/clientlibs/clientlib-base.css
http://localhost:4502/etc.clientlibs/<site>/clientlibs/clientlib-base.js

10.4 Matrix troubleshoot

SymptomCheckFix
CSS/JS không loadcategory string trong HTLkhớp categories trong .content.xml
404 /etc.clientlibs/...allowProxyset {Boolean}true + deploy
Deploy rồi vẫn không đổibrowser/dispatcher cache + rebuildinvalidate + rebuild libs
Load order saidependencies/embedchuyển libs shared sang dependencies; bundle app libs bằng embed
JS file không chạyjs.txt + path + #basethêm file vào js.txt, verify location

Liên kết nội bộ

AEM 6.5 On-Premise Developer Notes