{"id":22477473,"url":"https://github.com/orienteerbap/vuecket","last_synced_at":"2025-10-05T14:52:51.196Z","repository":{"id":81964953,"uuid":"284204319","full_name":"OrienteerBAP/vuecket","owner":"OrienteerBAP","description":"Power of Vue.JS married with magic of Apache Wicket","archived":false,"fork":false,"pushed_at":"2021-08-15T03:34:38.000Z","size":258,"stargazers_count":33,"open_issues_count":4,"forks_count":2,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-09-30T03:57:31.657Z","etag":null,"topics":["java","vue","vuejs","web-framework","webfr","wicket"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OrienteerBAP.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-08-01T06:44:42.000Z","updated_at":"2025-08-13T11:22:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"c76373b8-869f-4674-bc37-5214688ca685","html_url":"https://github.com/OrienteerBAP/vuecket","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/OrienteerBAP/vuecket","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrienteerBAP%2Fvuecket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrienteerBAP%2Fvuecket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrienteerBAP%2Fvuecket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrienteerBAP%2Fvuecket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OrienteerBAP","download_url":"https://codeload.github.com/OrienteerBAP/vuecket/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OrienteerBAP%2Fvuecket/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278470181,"owners_count":25992203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","vue","vuejs","web-framework","webfr","wicket"],"created_at":"2024-12-06T14:11:16.875Z","updated_at":"2025-10-05T14:52:51.160Z","avatar_url":"https://github.com/OrienteerBAP.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vuecket\nPower of [Vue.JS](https://vuejs.org/) married with magic of [Apache Wicket](https://wicket.apache.org/)\n\nVuecket allows to be reactive on frontend and backend without coding of REST services.\n\n## Content\n\n1. [Progress and Plans](#current-progress-and-plans)\n1. [Guiding Principles](#guiding-principles)\n1. [Enabling Vuecket](#enabling-vuecket)\n1. [Association of Wicket and Vue Components](#association-of-wicket-and-vue-components)\n1. [Server-side methods](#server-side-methods)\n1. [Subscribing to Vue Events](#subscribing-to-vue-events)\n1. [Watch data changes](#watch-data-changes)\n1. [Data Fibers](#data-fibers)\n\nOther documentation:\n* [VueJS + Apache Wicket = Vuecket](https://medium.com/@phantomydn/vuejs-wicket-vuecket-ee7bd5534fee) - Tutorial\n* [Знакомство с Vuecket](https://habr.com/ru/company/orienteer/blog/514938/) - Tutorial on russian\n\n## Current Progress and Plans\n\n- [X] Loading of Vue components code\n   - [X] From JSON configuration\n   - [X] From Vue files\n   - [X] From NPM packages\n- [X] Support of propogation of Vue events to server side: $on, $once, $watch\n- [ ] Support of data channels between server side and client\n   - [X] One Time - upon Vue component load\n   - [X] Observe - push changes to server side IMobel if they are changed on client one\n   - [X] Periodical refresh from server side\n   - [ ] WebSocket based refresh from server side\n- [X] Support of server based Vue methods\n\n## Guiding Principles\n\nVuecket idealogy following the following principals:\n\n1. Be declarative, not imperative\n   * You can use VueJS 3rd party libraries and get benefits out of Vuecket even without modifying them\n   * In a similar way, you can use 3rd party Apache Wicket component and just by adding VueBehavior (Behavior provided by Vuecket) you enable Vuecket benefits\n1. Provide 80% of functionality Out Of the Box, but do have good extension points for the remaining 20%\n\nAs you can see, btw, both Vue.Js and Apache Wicket fit this Guiding Principles as well. \n\n## Enabling Vuecket\n\nAdd the following dependency into your `pom.xml`:\n\n```xml\n\u003cdependency\u003e\n   \u003cgroupId\u003eorg.orienteer.vuecket\u003c/groupId\u003e\n   \u003cartifactId\u003evuecket\u003c/artifactId\u003e\n   \u003cversion\u003e${project.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nIf you are using `SNAPSHOT` version, please make sure that the following repository is included into your `pom.xml`:\n\n```xml\n\u003crepository\u003e\n\t\u003cid\u003eSonatype Nexus\u003c/id\u003e\n\t\u003curl\u003ehttps://oss.sonatype.org/content/repositories/snapshots/\u003c/url\u003e\n\t\u003creleases\u003e\n\t\t\u003cenabled\u003efalse\u003c/enabled\u003e\n\t\u003c/releases\u003e\n\t\u003csnapshots\u003e\n\t\t\u003cenabled\u003etrue\u003c/enabled\u003e\n\t\u003c/snapshots\u003e\n\u003c/repository\u003e\n```\n\n## Association of Wicket and Vue Components\n\nTo start using of Vuecket power you should associate your server-side component(Wicket) and client-side component(Vue.js).\nYou have 2 ways how to do that: \n* either through Annotations \n* or java code.\n\nVue.js components can be also defined by:\n* JSON description\n* VUE file\n* NPM package\n\n### Annotations\n\nThe following code will allow you to make from common Wicket Label component which supports Markdown\n```java\n@VueNpm(packageName = \"vue-markdown\", path = \"dist/vue-markdown.js\", enablement = \"Vue.use(VueMarkdown)\")\npublic class VueMarkdown extends Label {\n\n\tpublic VueMarkdown(String id, IModel\u003c?\u003e model) {\n\t\tsuper(id, model);\n\t}\n\n\tpublic VueMarkdown(String id, Serializable label) {\n\t\tsuper(id, label);\n\t}\n\n\tpublic VueMarkdown(String id) {\n\t\tsuper(id);\n\t}\n\t\n\t@Override\n\tprotected void onComponentTag(ComponentTag tag) {\n\t\ttag.setName(\"vue-markdown\");\n\t\tsuper.onComponentTag(tag);\n\t}\n}\n```\n\nCheck the following annotations: `@VueJson`, `@VueFile` and `@VueNpm`\n\n### Directly on Wicket Componet\n```java\nadd(new VueComponent\u003cString\u003e(\"app\")\n      .setVueDescriptor(\"{ data: { message : 'Hello Vue'}}\")\n);\n\nadd(new VueComponent\u003cString\u003e(\"app2\")\n      .setVueDescriptor(new PackageResourceReference(HomePage.class,\"HomePage.app2.vue\"))\n);\n\nadd(new Label(\"app3\").add(new VueBehavior(new VueJsonDescriptor(\"{ data: { message : 'Hello Vue'}}\"))));\n```\n\n## Server-side methods\n\nVuecket can work transparantly for Vue code. But you can add more spice by invoking server based methods from your Vue code.\n\nThere are 2 ways how you can use Vuecket server methods:\n\n* `vcInvoke` - asynchronous invokation of server method. No reply from server expected. But server side method has possiblity to \"push\" some changes to the client side, if needed.\n* `vcCall` - return Promise which will contain response from server side \n\nExample from test Vuecket application:\n\n```java\nadd(new VueComponent\u003cObject\u003e(\"app5\") {\n\t@VueMethod(\"count\")\n\tpublic void updateCountModel(IVuecketMethod.Context ctx, int count) {\n\t\tIVuecketMethod.pushDataPatch(ctx, \"server\", \"Hello from server #\"+count);\n\t}\n}.setVueDescriptor(\"{ data: { count : 0, server: 'Hello from client side' }}\"));\n```\n\n```html\n\u003cdiv\u003e\n\t\u003ch1\u003eApp #5\u003c/h1\u003e\n\t\u003cdiv wicket:id=\"app5\"\u003e\n\t\t\u003cbutton @click=\"count++; vcInvoke('count', count)\"\u003eClicked {{count}} times\u003c/button\u003e\n\t\t{{ server }}\n\t\u003c/div\u003e\n\u003c/div\u003e\n```\n\n## Subscribing to Vue Events\n\nIt might be helpful to subscribe to particular Vue Events on server side. To do that you can use `@VueOn` and `@VueOnce` annotations for methods which needs to be invoked if event occur on client side. Example:\n\n```java\n@VueOn(\"increase\")\npublic void showIncrease(int count) {\n\tSystem.out.println(\"On Increase called. Recieved count = \"+count);\n}\n```\n\n```html\n\u003cbutton @click=\"$emit('increase', count)\"\u003eTest Emit\u003c/button\u003e\n```\n\n## Watch data changes\n\nIn the similiar way you can subscribe server side method to changes of data on client side by using `@VueWatch` annotation\n\n```java\n@VueWatch(\"count\")\npublic void countChanged(Integer newCount, Integer oldCount) {\n\tSystem.out.println(\"Count changed from \"+oldCount+\" to \"+newCount);\n}\n```\n```html\n\u003cbutton @click=\"count++\"\u003eClicked {{count}} times\u003c/button\u003e\n```\n\n## Data Fibers\n\nData fiber is a way to synchronize data between server side and browser. There are different types of data-fibers\n\n* `load` - data will be provided only for initial Vue component loading\n* `observe` - data will be sent back to server upon any change\n* `refresh` - data periodically checked for changes and if there are any - they will be uploaded\n* `wspush` - data pushed to client server through WebSocket if there are changes (NOT YET SUPPORTED)\n\nExample:\n\n```java\n//Value of this model will be initially load to all connected clients and then kept update upon changes\nprivate static final IModel\u003cString\u003e HELLO_MODEL = Model.of(\"Hello from server\");\n...\nVueComponent\u003cObject\u003e app6 = new VueComponent\u003cObject\u003e(\"app6\", HELLO_MODEL)\n\t\t\t\t.setVueDescriptor(\"{ data: { text : 'Hello Vue'}}\")\n\t\t\t\t.addDataFiber(\"text\");  // \u003c===Pay attention to this call. It binds default IModel to 'text' data fiber\napp6.add(new VueMarkdown(\"markdown\", \"\"));\nadd(app6);\n```\n```html\n\u003cdiv\u003e\n\t\u003ch1\u003eApp #6\u003c/h1\u003e\n\t\u003cdiv wicket:id=\"app6\"\u003e\n\t\t\u003ctextarea v-model=\"text\"\u003e\u003c/textarea\u003e\n\t\t\u003cvue-markdown wicket:id=\"markdown\" v-bind:source=\"text\"\u003eApplication 6\u003c/vue-markdown\u003e\n\t\u003c/div\u003e\n\u003c/div\u003e\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forienteerbap%2Fvuecket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forienteerbap%2Fvuecket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forienteerbap%2Fvuecket/lists"}