왜 바닐라프론트를 만들었나!!

ExtJS 사용자를 위한 다음 단계: VanillaFront

VanillaFront 2026. 9. 18. 23:08

시작하며

ExtJS는 훌륭한 프레임워크였고, 지금도 많은 한국 기업의 사내 시스템·관리자 페이지·대시보드를 돌리고 있습니다. 그리드·폼·레이아웃이 한 세트로 제공되는 "batteries included" 철학은 사내 시스템처럼 화면 수가 많고 시각적 통일성이 중요한 프로젝트에 정확히 맞았습니다.

하지만 2020년대 중반, ExtJS를 유지하는 개발팀은 몇 가지 무거운 질문에 직면합니다.

  • Sencha가 Idera에 인수된 후 라이선스 정책·가격이 강화되었고,
  • ExtJS 4/5는 사실상 EOL, 모던 브라우저 대응·보안 패치가 부담이 되며,
  • 모던 개발 워크플로우 (AI 코드 생성, VSCode 통합) 와 거리가 멀어졌습니다.

이 글은 그런 팀들에게 VanillaFront가 왜 자연스러운 다음 단계가 되는지 — 익숙한 것은 그대로 가져오면서 20년 축적된 웹 표준으로 인프라를 새로 짠 모습을 — 정리합니다.

왜 React·Vue로 안 가고 VanillaFront인가

React·Vue도 훌륭한 선택이지만, ExtJS를 쓰던 팀에게는 여러 층의 갭이 있습니다.

갭 1: 컴포넌트 조합의 비용 ExtJS는 한 패키지 안에 그리드·트리·차트·폼·레이아웃이 모두 들어 있습니다. React·Vue로 가면 이 각각을 골라 조합해야 하고, 엔터프라이즈급 그리드 기능은 대부분 유료 티어 (AG Grid Enterprise, Handsontable Pro 등) 입니다.

갭 2: 개발 모델의 차이 ExtJS는 선언적 config 객체 트리 ({xtype: 'panel', items: [...]}) 로 화면을 정의합니다. React는 JSX + hooks + 상태 관리 모델. 사내 시스템처럼 화면 수 많은 프로젝트에서는 이 패러다임 시프트가 무겁습니다.

갭 3: 빌드 파이프라인 ExtJS는 Sencha Cmd 하나로 빌드했습니다. React·Vue로 가면 Webpack·Vite·Node·npm 생태계 전체를 감당해야 합니다. 사내 인트라넷 환경에선 종종 이게 최대 장벽입니다.

VanillaFront는 ExtJS와 같은 철학을 유지합니다.

  •  선언적 config 트리 — ExtJS의 xtype → VanillaFront의 tagName
  •  모든 컴포넌트가 한 패키지 — Grid, Chart, Diagram, Form, Layout 통합
  •  빌드 파이프라인 불필요 — ES6 모듈 브라우저 직접 로드
  •  엔터프라이즈 그리드 기능 포함 — 별도 라이선스 없이

패러다임 시프트 없이 옮길 수 있는 몇 안 되는 선택지입니다.

개념 매핑

ExtJS를 알던 개발자는 아래 매핑만 익히면 80%는 즉시 이해합니다.

1. View 정의 스타일

ExtJS

Ext.define('MyApp.view.CustomerPanel', {
    extend: 'Ext.panel.Panel',
    xtype: 'customer-panel',
    title: '고객 정보',
    layout: 'vbox',
    items: [
        { xtype: 'textfield', fieldLabel: '이름' }
    ]
});

VanillaFront

import Va from '../../lib/va.js';

export default class CustomerPanel extends Va.View {
    constructor(){ super(arguments); }
    mounted(){ /* DOM 부착 후 초기화 */ }
    config(){
        return {
            tagName: 'article',
            layout: 'ds-flex fd-column ai-stretch gap-s',
            tags: [
                { tagName: 'h1', innerHTML: '고객 정보' },
                { tagName: 'combobox', label: '이름', style: { width: '270px' } }
            ]
        };
    }
}
Va.registerView('/view/customer/CustomerPanel', CustomerPanel);

핵심 매핑

  • Ext.define / extend: 'Ext.panel.Panel'  class extends Va.View
  • xtype  tagName
  • items  tags
  • layout: 'vbox'  layout: 'ds-flex fd-column'
  • Ext.create()  Va.registerView('/path', Class)

2. Page / Panel 컨테이너

VanillaFront에서 화면의 표준 구조는 Page → Panel 조합입니다. ExtJS의 border layout + Panel 구조와 대응됩니다.

ExtJS (border layout)

{
    layout: 'border',
    items: [
        { region: 'north', title: '헤더', height: 80 },
        { region: 'west', title: '메뉴', width: 200 },
        { region: 'center', title: '내용' }
    ]
}

VanillaFront (page + panel)

{
    tagName: 'page',
    tags: [
        { tagName: 'panel', style: 'height:80px', innerHTML: '헤더' },
        {
            tagName: 'div',
            layout: 'ds-flex fd-row ai-stretch gap-s',
            style: 'flex:1',
            tags: [
                { tagName: 'panel', style: 'width:200px', innerHTML: '메뉴' },
                { tagName: 'panel', style: 'flex:1', innerHTML: '내용' }
            ]
        }
    ]
}

Page/Panel 자체가 표준 간격 (gap) 을 갖기 때문에 사이에 별도 margin/padding을 강제로 넣지 않아도 자연스러운 룩이 나옵니다.

3. 그리드 — 가장 큰 관심사

ExtJS

{
    xtype: 'grid',
    store: customerStore,
    columns: [
        { text: '품목그룹코드', dataIndex: 'itemGroupId', width: 100 },
        { text: '품목그룹', dataIndex: 'itemGroupName', width: 100 },
        { text: '품명', dataIndex: 'itemName', flex: 1 },
        { text: '금액', dataIndex: 'amt', xtype: 'numbercolumn', align: 'right', width: 100 }
    ]
}

VanillaFront

{
    ref: 'refGrid',
    tagName: 'grid',
    selectType: 'singleSelect',
    style: { height: '400px', width: '100%' },
    columns: [
        { key: 'itemGroupId', title: '품목그룹코드', width: 100 },
        { key: 'itemGroupName', title: '품목그룹', width: 100 },
        { key: 'itemName', title: '품명', fillRatio: 1, minWidth: 100 },
        { key: 'amt', title: '금액', type: 'number', align: 'right', width: 100 }
    ]
}

컬럼 속성 매핑

  • text  title
  • dataIndex  key
  • flex  fillRatio
  • xtype: 'numbercolumn'  type: 'number'
  • xtype: 'datecolumn'  type: 'date'

데이터 로드 ExtJS의 Store 자동 로드와 달리, VanillaFront는 서비스에서 데이터 받아 명시적으로 setData():

mounted(){
    this.onSearch();
}
onSearch(){
    ItemService.getItemList(this, {}, (me, ok, res) => {
        if(ok) me.getRef('refGrid').setData(res.data.list);
    });
}

행 데이터 조작 API

this.getRef('refGrid').addData({itemId:'999', itemName:'추가품목'});
this.getRef('refGrid').insertData(newRow, targetData);
this.getRef('refGrid').modifyData(selectedData);
this.getRef('refGrid').removeData(selectedData);
// 변경 추적
this.getRef('refGrid').getAddedData();
this.getRef('refGrid').getModifiedData();
this.getRef('refGrid').getRemovedData();
this.getRef('refGrid').commit();     // 변경 확정
this.getRef('refGrid').rollback();   // 변경 취소

ExtJS의 store.getUpdatedRecords(), store.getRemovedRecords() 와 같은 개념. 변경 추적이 그리드에 기본 내장되어 있어 서버 동기화 처리가 단순합니다.

4. 그룹핑 / 요약

ExtJS

{
    xtype: 'grid',
    features: [{ ftype: 'grouping' }, { ftype: 'summary' }],
    columns: [
        { text: '금액', dataIndex: 'amt', summaryType: 'sum' }
    ]
}

VanillaFront

{
    tagName: 'grid',
    groupColumns: [
        { key: 'itemGroupId', summary: true },
        { key: 'itemGroupName', summary: false }
    ],
    summaryColumns: true,
    summaryBottom: true,
    columns: [
        {
            key: 'amt', title: '금액', type: 'number', align: 'right', width: 100,
            onGroupingRender: 'onGroupingRender',
            onSummaryRender: 'onSummaryRender'
        }
    ]
}

그룹·요약 렌더링은 뷰 메서드로 위임:

onGroupingRender(grid, key, vals, data, column, rowIndex, colIndex, row, col, cell){
    let sum = vals.reduce((a, v) => a + Va.Util.getFixedNumber(v), 0);
    cell.innerHTML = '금액: ' + Va.Util.getRound(sum, 3) + '원';
}

5. 셀 편집 (FlashTag)

ExtJS의 plugins: 'cellediting' 에 해당하는 개념이 VanillaFront에는 flashTag 로 구현되어 있습니다. 편집 시점에 해당 셀에 원하는 컴포넌트를 일시 렌더링:

{
    key: 'itemName',
    title: '품명',
    flashTag: { tagName: 'input' },
    onEdit: 'onColumnEdit'
},
{
    key: 'createDate',
    title: '날짜',
    type: 'date',
    flashTag: { tagName: 'datePicker' },
    onEditRaw: 'onColumnEditRaw'
}

편집 컴포넌트 종류를 셀별로 자유롭게 선택 가능 (input, combobox, datePicker, 사용자 정의 컴포넌트 등).

6. 콤보박스 (Combobox)

ExtJS

{
    xtype: 'combobox',
    fieldLabel: '지역',
    store: regionStore,
    valueField: 'code',
    displayField: 'name'
}

VanillaFront

{
    tagName: 'combobox',
    label: '지역',
    key: 'code',
    display: 'name',
    data: [
        { code: 'SEO', name: '서울' },
        { code: 'BSN', name: '부산' }
    ],
    style: { width: '270px' }
}
  • fieldLabel  label
  • valueField  key
  • displayField  display
  • store  data (인라인) 또는 .setData()

체크박스 선택형·다중 선택 등도 인라인 template 로 자유롭게:

{
    tagName: 'combobox',
    multiSelect: true,
    addCheckAll: true,
    clickToSelect: true,
    template: {
        tagName: 'listItem',
        layout: 'ds-flex fd-row ai-center',
        tags: [
            { tagName: 'checkbox', checked: '{vaDataSelected}' },
            { tagName: 'div', innerHTML: '{display}' }
        ]
    },
    data: [/* ... */]
}

7. 레이아웃

ExtJSVanillaFront

layout: 'vbox' layout: 'ds-flex fd-column'
layout: 'hbox' layout: 'ds-flex fd-row'
layout: 'fit' 자식 style: 'flex:1'
layout: 'border' Page/Panel 조합 + flex 비율
align: 'stretch' ai-stretch
pack: 'center' jc-center

CSS Flexbox 기반 — 브라우저 devtools에서 즉시 이해·수정 가능. ExtJS 레이아웃처럼 JS 계산 오버헤드 없음.

8. 이벤트

ExtJS

Ext.create('Ext.button.Button', {
    text: '저장',
    handler: function() { /* ... */ }
});
grid.on('cellclick', function(view, cell, cellIndex, record) { /* ... */ });

VanillaFront

{
    tagName: 'button',
    text: '저장',
    appearance: 'primary',
    onClick: 'onSaveClick'    // 뷰 메서드명 참조
},
{
    tagName: 'grid',
    onRowClick: 'onRowClick',
    onEdit: 'onEdit'
}

뷰 클래스에 메서드로 정의:

onSaveClick(button, event){ /* ... */ }
onRowClick(grid, key, value, data, column, rowIndex, colIndex, row, col, cell, evt){ /* ... */ }

문자열 참조 방식이라 config 트리 안에 함수 클로저가 쌓이지 않아 가독성이 유지됩니다.


여기서부터는 명확히 더 나아진 부분

지금까지는 "익숙한 개념을 그대로 옮길 수 있다"는 이야기였습니다. 하지만 VanillaFront가 단순히 ExtJS의 저렴한 복제품인 건 아닙니다. 아키텍처 몇 가지는 20년 축적된 웹 표준·개발자 경험을 반영해서 명확히 개선되어 있습니다.

1. 순수 ES6 클래스 — 커스텀 클래스 시스템 없음

ExtJS는 자체 클래스 시스템 (Ext.define, extend, mixins, requires) 을 20년 넘게 유지해왔습니다. 이건 ES6 클래스가 표준화되기 전 시대의 산물이고, 지금도 여전히 사용하는 개발자는 JavaScript 표준이 아닌 ExtJS 방언을 배워야 합니다.

ExtJS

Ext.define('MyApp.view.CustomerList', {
    extend: 'Ext.grid.Panel',
    xtype: 'customer-list',
    requires: [
        'MyApp.store.Customers',
        'Ext.grid.column.Number'
    ],
    mixins: {
        observable: 'Ext.util.Observable'
    },
    initComponent: function() {
        this.callParent();
    }
});

VanillaFront

import Va from '../../lib/va.js';
import CustomerModel from './CustomerModel.js';

export default class CustomerList extends Va.View {
    constructor(){ super(arguments); }
    mounted(){ /* DOM 준비 완료 */ }
    config(){ return { tagName: 'grid', /* ... */ }; }
}
Va.registerView('/view/customer/CustomerList', CustomerList);

차이가 만드는 실질적 이득

  •  IDE 지원이 그냥 됩니다 — VSCode·가 클래스·상속·자동완성을 표준 방식으로 처리. ExtJS는 별도 플러그인·정의 파일 필요
  •  
  •  표준 JS 지식이 그대로 통함 — 신입 개발자가 ExtJS 클래스 시스템 배우는 시간이 없음
  •  import/export ES6 모듈  requires 대신 표준 모듈 시스템. 정적 분석 도구·번들러 모두 이해
  •  super, extends, async/await 등 모던 JS 기능 자연스럽게 사용

"ExtJS 방언"이 아니라 그냥 "모던 JavaScript" 로 코드가 굴러갑니다.

2. Shadow DOM 기반 컴포넌트 격리

ExtJS는 전역 CSS 클래스 (.x-btn, .x-panel-body, .x-grid-cell) 로 컴포넌트를 스타일링합니다. 이게 의도치 않은 결과를 낳습니다.

  • 페이지에 임베드하면 호스트 사이트 CSS와 충돌
  • 여러 ExtJS 버전을 한 페이지에 못 씀
  • 사용자 정의 스타일이 의도치 않게 전역 오염
  • ExtJS 클래스명을 실수로 다른 곳에서 쓰면 스타일 깨짐

VanillaFront는 각 컴포넌트가 자체 Shadow DOM 을 가집니다:

// va.js 내부 (컴포넌트 초기화 로직 발췌)
if(this.element.shadowRoot == null){
    this.shadowEl = this.element.attachShadow({mode:'open'});
}

실질적 이득

  •  완전한 CSS 격리 — 컴포넌트 스타일이 밖으로 새지 않고, 밖의 스타일이 안으로 침투하지 않음
  •  호스트 사이트에 부담 없이 임베드 — 기존 시스템 페이지에 VanillaFront 화면을 iframe 없이 넣어도 스타일 안 깨짐 (VSCode Extension이 편집 프리뷰를 이 방식으로 렌더링)
  •  여러 테마 동시 사용 가능 — 한 페이지에 Light 테마 컴포넌트와 Dark 테마 컴포넌트가 나란히 있어도 서로 영향 X
  •  다른 프레임워크와 공존 — React 앱에 VanillaFront 그리드를 올려도 스타일 충돌 없음. 점진적 이관 시 결정적 이점

ExtJS 시대에는 Shadow DOM이 없었기에 이 접근이 불가능했습니다. 지금은 표준 브라우저 기능이라 안 쓸 이유가 없는데, ExtJS는 코어를 갈아엎지 않는 한 되돌리기 어렵습니다.

3. MVP 아키텍처 — Presenter로 명확히 분리

  • 3. 명료한 View 클래스 — 한 파일에 모든 것
    import Va from '../../lib/va.js';
    import ItemService from '../../service/ItemService.js';
    
    export default class CustomerList extends Va.View {
        constructor(){ super(arguments); }
    
        mounted(){
            this.onSearch();
        }
    
        onSearch(){
            ItemService.getItemList(this, {}, (me, ok, res) => {
                if(ok) me.getRef('refGrid').setData(res.data.list);
            });
        }
    
        onRowClick(grid, key, value, data, column, rowIndex, colIndex, row, col, cell, evt){
            this.getRef('itemId').setValue(data.itemId);
            this.getRef('itemName').setValue(data.itemName);
        }
    
        onAdd(){
            this.getRef('refGrid').addData({ itemId:'999', itemName:'신규 품목' });
        }
    
        config(){
            return {
                tagName: 'article',
                layout: 'ds-flex fd-column ai-stretch gap-s',
                tags: [
                    {
                        ref: 'refGrid',
                        tagName: 'grid',
                        onRowClick: 'onRowClick',
                        columns: [
                            { key: 'itemId',   title: '품목코드' },
                            { key: 'itemName', title: '품명' }
                        ]
                    },
                    { tagName: 'button', text: '추가', onClick: 'onAdd' }
                ]
            };
        }
    }
    Va.registerView('/view/customer/CustomerList', CustomerList);
    
    한 파일에 다 있어서 좋은 점
    •  화면 하나 = 파일 하나 원칙 — 파일 이동 없이 완결. "이 화면 뭐 하는 거지?" 를 한 파일 스크롤로 파악
    •  AI 친화적 — "이 화면 만들어" 요청 시 한 파일 완결로 나옴. 파일 간 왕복이 없어 컨텍스트 길이 절약
    •  코드 리뷰가 짧음 — PR diff가 한 파일에 모여 있음
    •  ES6 표준 클래스 — IDE 자동완성·rename·jump-to-definition 이 완벽 지원. ExtJS는 별도 도구 필요
  • VanillaFront는 한 View 클래스에 config, 이벤트 핸들러, 라이프사이클 훅이 모두 들어가는 단순한 구조입니다. ExtJS의 initComponent + listeners + handler 조합과 개념은 비슷하지만, ES6 표준 클래스 위에 얹혀 있어 훨씬 명료합니다.

 

4. 중앙 라우터 — 한 파일에 전체 라우트 조망

ExtJS의 Router는 컨트롤러별로 분산 정의됩니다. 프로젝트 규모가 커지면 "이 URL이 어느 뷰로 가지?" 를 찾기 위해 여러 파일을 뒤져야 합니다.

VanillaFront는 router.js 파일 하나에 전체 라우트 맵이 모여 있습니다:

const routerPath = {
    main:               { path: '/view/main/Main' },
    apibutton:          { path: '/view/api/buttons/ApiButton', areas: ['main'] },
    apigrid:            { path: '/view/api/grids/ApiGrid' },
    tmplgridandform:    { path: '/view/tmpl/grid/TmplGridAndForm' },
    price:              { path: '/view/price/Price' },
    // ... 400+ 라우트
};
Va.setRouterPath(routerPath);

이득

  •  전체 사이트 라우트 한눈에 조망 — 400+ 라우트도 하나의 객체에서 검색 가능
  •  areas 개념으로 다영역 레이아웃 지원 — 라우트가 어느 영역에 렌더될지 명시적 지정
  •  동적 로딩 — 각 라우트가 처음 접근될 때 View 파일 lazy-load. 초기 번들 크기 최소
  •  URL 파라미터·상태 전달 — RouterParams, RouterState 패턴이 프레임워크 표준으로 제공

ExtJS의 Ext.util.History + Controller 조합보다 훨씬 명료합니다.

5. Config가 순수 데이터 — AI 시대의 결정적 차이

이건 별도 섹션으로 다룰 만큼 중요한 차이입니다.

ExtJS

Ext.create('Ext.panel.Panel', {
    items: [{
        xtype: 'button',
        handler: function(btn) {
            // 함수 클로저 — 직렬화 불가
            this.doSomething();
        }
    }]
});

handler 자리에 함수가 직접 들어갑니다. 이 트리는 직렬화가 불가능하고, AI가 코드를 생성할 때 함수 컨텍스트를 예측해야 하며, WYSIWYG 에디터가 파싱하기 까다롭습니다.

VanillaFront

{
    tagName: 'panel',
    tags: [{
        tagName: 'button',
        text: '저장',
        onClick: 'onSaveClick'   // 문자열 참조
    }]
}

onClick은 뷰/프레젠터의 메서드명 문자열입니다. 트리 전체가 순수 데이터 (JSON 화 가능).

이 순수 데이터 구조가 만드는 것

  •  AI가 이해·생성 가능 — LLM이 JSON 트리를 다루는 건 함수 클로저를 다루는 것보다 훨씬 쉬움
  •  WYSIWYG 에디터가 파싱·시각화·수정 가능 — VSCode Extension의 실시간 편집이 여기서 나옴
  •  저장·복원·마이그레이션이 순수 데이터 변환 — Config 트리를 다른 스키마로 옮기는 스크립트가 간단
  •  Diff·리뷰가 쉬움 — Git diff가 데이터 변화로 읽힘, 함수 리팩토링 노이즈 없음

이게 왜 결정적인가: AI 개발 시대에 프레임워크의 컴포넌트 트리가 "코드"인지 "데이터"인지가 도구 통합의 갈림길입니다. ExtJS 시대의 프레임워크는 "코드" 기반이라 AI·비주얼 편집기와 자연스럽게 통합되기 어렵고, VanillaFront처럼 처음부터 "데이터" 기반으로 설계된 프레임워크가 이 시대에 유리합니다.


정리 — 왜 그냥 복사가 아닌가

영역ExtJSVanillaFront

클래스 시스템 Ext.define (커스텀) 표준 ES6 class extends
모듈 시스템 requires (커스텀) 표준 ES6 import/export
컴포넌트 격리 전역 CSS 클래스 Shadow DOM 격리
아키텍처 패턴 MVC/MVVM (혼재 흔함) MVP (View/Presenter/Model 명확 분리)
라우터 컨트롤러별 분산 중앙 등록소 (router.js)
Config 표현 함수 클로저 혼합 순수 데이터 트리
AI 워크플로우 통합 어려움 설계 시점부터 고려됨
CSS 파이프라인 Sass 빌드 필요 CSS 변수 + Shadow DOM 스코프

"ExtJS를 더 싸게" 가 아니라, "ExtJS 이후 20년 웹 표준·개발자 경험을 반영해서 다시 설계한 같은 계열의 프레임워크" 입니다. 익숙한 config 트리·컴포넌트 세트는 그대로 오되, 그 아래 인프라는 표준 웹으로 갈아입은 셈입니다.


마이그레이션 접근법

한 번에 전부 옮기는 big-bang은 위험합니다. 실전 순서:

  1. 신규 화면부터 — 지금 새로 만드는 화면 하나를 VanillaFront로. 팀이 개념을 익히는 기간
  2. 독립 화면 이관 — 종속성 낮은 작은 화면 (설정, 사용자 관리 등) 부터 대체. 프로세스·검증 방식 확립
  3. 공통 패턴 표준화 — 사내에서 반복되는 패턴 (조회조건 폼, 페이지네이션 그리드, 마스터-디테일) 을 View 클래스로 표준화
  4. 핵심 화면 이관 — 복잡한 그리드·다이어그램 화면. 이 시점이면 팀이 이미 능숙
  5. ExtJS 제거 — 남은 화면 정리, 라이선스 갱신 중단

한 화면당 이관 시간은 익숙해지면 원본 개발 시간의 20~40% 수준. 개념 매핑이 거의 일대일이라 코드 이식이 대부분입니다.

ExtJS에서 못 하던 것 — 새로운 개발 경험

위에서 본 순수 데이터 config 구조 덕분에 다음이 가능해집니다.

AI 코드 생성 + 즉시 시각화

VanillaFront에는 VSCode Extension이 있고, 그 안에 WYSIWYG 에디터가 통합되어 있습니다.

  • ChatGPT / Claude에게 "고객 관리 화면 만들어" 요청 → VanillaFront 코드 반환
  • VSCode에서 파일 열면 에디터 영역에 즉시 렌더링 (Shadow DOM 격리 프리뷰)
  • 마우스로 수정 → 자동으로 파일에 저장
  • Undo/Redo, 파일 목록, 컴포넌트 팔레트 전부 IDE 안에서 동작

ExtJS Architect가 있었지만 별도 프로그램·별도 라이선스였고, AI 통합은 없었습니다. AI + 시각 편집 + IDE 내 저장의 조합은 현재 국내 UI 프레임워크 중 유일합니다.

번들러 없이 배포

ExtJS는 Sencha Cmd로 빌드했지만 여전히 파이프라인이었습니다. VanillaFront는 ES6 모듈을 브라우저가 직접 로드합니다. 파일 수정 → 브라우저 새로고침으로 끝. CI 파이프라인 없이 사내 인트라넷에도 즉시 배포.

22개 테마 + 즉시 전환

Light, Dark, Paper, Titan 등 11종 × tight 변형 = 22개 테마. 사용자별 저장, 다크모드 대응이 프레임워크 레벨에서 지원됩니다.

라이선스 비교

항목ExtJS (엔터프라이즈)VanillaFront

개인/소규모 상업 사용 개발자당 유료 Basic 250만원~
엔터프라이즈 종합 개발자당 연 라이선스, 프로젝트당 수천만 원 규모 Enterprise 550만원~
그리드 엔터프라이즈 기능 상위 티어에서 기본 포함
편집기 (Designer/Editor) Architect 별도 라이선스 Enterprise 티어에 VSCode Extension 포함

가격은 시장 통용 감각. 정확한 견적은 각 벤더 공식 안내 기준.

ExtJS Enterprise 대비 약 1/10 수준으로 종합 기능을 확보할 수 있습니다.

어떤 팀이 지금 검토하면 좋은가

VanillaFront가 ExtJS의 완벽한 상위호환은 아닙니다. 특정 컴포넌트나 기능은 아직 갭이 있을 수 있고, 대형 벤더의 24/7 지원 조직은 없습니다.

하지만 아래에 해당하시면 진지하게 검토해 볼 만합니다.

  • ExtJS 4/5/6 사용 중이고 EOL·라이선스 부담을 느낌
  • React·Vue 이관을 검토했지만 컴포넌트 조합·빌드 부담이 걸림
  • 선언적 config 트리 방식을 유지하고 싶음
  • AI 개발 워크플로우 통합에 관심 있음
  • 그리드·차트·다이어그램이 프로젝트 중심 컴포넌트