Skip to content

Commit eee85fc

Browse files
Merge pull request #29 from AdobeDocs/vue-starter-sample
Adds vue-starter sample add-on
2 parents 7dc5e09 + 1dd0032 commit eee85fc

File tree

8 files changed

+471
-0
lines changed

8 files changed

+471
-0
lines changed

contributed/vue-starter/README.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Vue Starter - Adobe Express Add-on
2+
3+
A sample Adobe Express Add-on that demonstrates how to build an add-on using Vue.js and properly access the Adobe Express Add-on SDK.
4+
5+
## What This App Does
6+
7+
This starter sample demonstrates a best practice approach for integrating Vue.js with the Adobe Express Add-on SDK:
8+
9+
1. **SDK Integration via Dependency Injection**: The app uses Vue's provide/inject pattern to make the Adobe Express SDK available throughout the component tree.
10+
11+
2. **Asynchronous SDK Loading**: The Add-on UI SDK is loaded asynchronously and initialized before the Vue app is mounted, ensuring that the SDK is ready for use when components need it.
12+
13+
3. **Simple Interactive UI**: A single button demonstrates reactive UI updates when clicked, displaying information about the loaded SDK.
14+
15+
4. **Component Structure**: Follows Vue.js best practices with a clean separation of concerns between template, logic, and styling using Single-File Components.
16+
17+
## Key Implementation Details
18+
19+
The application implements the following pattern:
20+
21+
1. **index.js**: Loads the SDK asynchronously using dynamic imports, makes it available via Vue's provide/inject system, and mounts the app.
22+
23+
2. **App.vue**: Injects the SDK and uses it to display details in response to user interaction.
24+
25+
## Overview
26+
27+
This project showcases:
28+
29+
- Vue.js integration with Adobe Express Add-ons
30+
- Single-file component (SFC) architecture
31+
- Proper SDK injection pattern using Vue's dependency injection
32+
- Asynchronous SDK initialization
33+
- Webpack build configuration for Vue.js
34+
- ES modules with proper import/export syntax
35+
36+
## Technologies Used
37+
38+
- HTML
39+
- CSS
40+
- JavaScript
41+
- Vue.js 3.x (Composition API)
42+
- Adobe Express Add-on SDK
43+
- Webpack 5
44+
- ES Modules
45+
46+
## Features
47+
48+
- Reactive UI components with Vue.js
49+
- Adobe Express Add-on SDK integration via dependency injection
50+
- Button component that displays SDK information when clicked
51+
- Fully commented code for beginners to understand Vue.js concepts
52+
53+
## Project Structure
54+
55+
- `src/`: Source code
56+
- `App.vue`: Main Vue component with detailed comments explaining Vue concepts
57+
- `index.js`: Entry point that loads the SDK and mounts the Vue app
58+
- `index.html`: HTML template with the Vue mounting point
59+
- `manifest.json`: Add-on manifest defining the add-on properties
60+
61+
## Getting Started
62+
63+
### Prerequisites
64+
65+
- Node.js 18.x or higher
66+
- npm 9.x or higher
67+
- Adobe Express account
68+
69+
### Installation
70+
71+
1. Clone the repository
72+
2. Install dependencies:
73+
```
74+
npm install
75+
```
76+
77+
### Development
78+
79+
Start the development server:
80+
```
81+
npm run start
82+
```
83+
84+
This will launch a development server and open the add-on in your browser.
85+
86+
### Building
87+
88+
Build the add-on for production:
89+
```
90+
npm run build
91+
```
92+
93+
### Packaging
94+
95+
Create a distributable package:
96+
```
97+
npm run package
98+
```
99+
100+
## Working with the Add-on
101+
102+
1. After starting the development server, the add-on will appear in your browser
103+
2. Click the "Click me" button to see information about the Adobe Express Add-on SDK
104+
3. The button text will change to "Clicked" and the SDK details will be logged to the console
105+
106+
## Learning from this Example
107+
108+
This project is heavily commented to help beginners understand:
109+
110+
1. **Vue.js Fundamentals**: Component structure, reactive data, event handling
111+
2. **Composition API**: Using `ref`, `onMounted`, and `inject`
112+
3. **SDK Integration**: Proper patterns for initializing and using the Adobe Express Add-on SDK
113+
4. **ES Module Usage**: Modern JavaScript import/export syntax
114+
115+
## Customization
116+
117+
You can use this sample as a starting point for your own Adobe Express Add-ons with Vue.js:
118+
119+
1. Modify `App.vue` to create your own components and UI
120+
2. Add additional Vue components as needed
121+
3. Update the manifest.json to change your add-on's metadata
122+
123+
## Troubleshooting
124+
125+
- If you encounter module resolution issues, check that "type": "module" is correctly set in package.json
126+
- For webpack configuration issues, review webpack.config.js
127+
- If the SDK isn't available in your components, ensure you're using the inject pattern correctly
128+
129+
## Resources
130+
131+
- [Adobe Express Add-ons Documentation](https://developer.adobe.com/express/add-ons/)
132+
- [Vue.js Documentation](https://vuejs.org/guide/introduction.html)
133+
- [Vue Composition API Guide](https://vuejs.org/guide/extras/composition-api-faq.html)
134+
- [Webpack Documentation](https://webpack.js.org/concepts/)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"name": "vue-starter",
3+
"version": "1.0.0",
4+
"description": "Adobe Creative Cloud Web Add-on using Vue.js",
5+
"type": "module",
6+
"scripts": {
7+
"clean": "ccweb-add-on-scripts clean",
8+
"build": "ccweb-add-on-scripts build --use webpack",
9+
"start": "ccweb-add-on-scripts start --use webpack",
10+
"package": "ccweb-add-on-scripts package --use webpack"
11+
},
12+
"keywords": [
13+
"Adobe",
14+
"Creative Cloud Web",
15+
"Add-on",
16+
"panel",
17+
"Vue.js"
18+
],
19+
"dependencies": {
20+
"vue": "^3.4.21"
21+
},
22+
"devDependencies": {
23+
"@adobe/ccweb-add-on-scripts": "^3.0.0",
24+
"@types/adobe__ccweb-add-on-sdk": "^1.3.0",
25+
"@vitejs/plugin-vue": "^5.0.4",
26+
"@vue/compiler-sfc": "^3.4.21",
27+
"typescript": "^5.4.2",
28+
"vite": "^5.1.6",
29+
"babel-loader": "9.1.3",
30+
"@babel/core": "7.23.3",
31+
"@babel/preset-env": "7.23.3",
32+
"@babel/preset-react": "7.23.3",
33+
"copy-webpack-plugin": "11.0.0",
34+
"css-loader": "6.8.1",
35+
"html-webpack-plugin": "5.5.3",
36+
"style-loader": "3.3.3",
37+
"vue-loader": "^17.4.2",
38+
"vue-style-loader": "^4.1.3",
39+
"webpack": "5.89.0",
40+
"webpack-cli": "5.1.4"
41+
}
42+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<template>
2+
<!--
3+
This is the template section where we define the HTML structure of our component.
4+
In Vue, we use a single-file component (SFC) approach that combines template, logic, and styles.
5+
-->
6+
<!--
7+
Please note that this document does not use the spectrum web components theme for Express.
8+
You may use "addOnUISdk.app.ui.theme" to get the current theme and style accordingly.
9+
-->
10+
11+
<div class="container">
12+
<!--
13+
Vue directives start with ':' or 'v-' and provide special functionality:
14+
- :disabled is a shorthand for v-bind:disabled, which binds the disabled attribute to the isReady state
15+
- @click is a shorthand for v-on:click, which attaches a click event handler
16+
- {{ buttonText }} is a template expression that displays the value of buttonText reactive variable
17+
-->
18+
<button :disabled="!isReady" @click="handleClick">{{ buttonText }}</button>
19+
</div>
20+
</template>
21+
22+
<script>
23+
// Import necessary functions from Vue's Composition API
24+
import { ref, onMounted, readonly, inject } from 'vue'
25+
26+
export default {
27+
// Name of the component for debugging purposes
28+
name: 'App',
29+
30+
// The setup() function is the entry point for Vue's Composition API
31+
setup() {
32+
// Create reactive state variables using ref()
33+
// These will automatically update the UI when their values change
34+
const isReady = ref(false); // Controls button disabled state
35+
const buttonText = ref('Click me');
36+
37+
// Inject the Adobe Express SDK that was provided in index.js
38+
// This makes the SDK available only in this component without global variables
39+
const addOnUISdk = inject('addOnUISdk');
40+
41+
// Define the function that runs when the button is clicked
42+
const handleClick = async () => {
43+
// Update the button text (UI will automatically update)
44+
buttonText.value = 'Clicked'
45+
46+
// Log the SDK details to the console
47+
console.table(JSON.stringify(addOnUISdk));
48+
}
49+
50+
// onMounted lifecycle hook runs after the component is mounted to the DOM
51+
onMounted(async () => {
52+
console.log("App.vue is ready for use.")
53+
// Enable the button once the component is mounted
54+
isReady.value = true
55+
});
56+
57+
// Values returned from setup() are exposed to the template
58+
return {
59+
isReady,
60+
buttonText,
61+
handleClick
62+
}
63+
}
64+
}
65+
</script>
66+
67+
<style>
68+
/* CSS styles for the component */
69+
.container {
70+
margin: 24px;
71+
display: flex;
72+
flex-direction: column;
73+
}
74+
75+
button {
76+
background-color: rgb(82, 88, 228); /* Adobe blue color */
77+
border-color: rgb(82, 88, 228);
78+
border-radius: 16px;
79+
border-style: solid;
80+
color: rgb(255, 255, 255); /* White text */
81+
font-family: sans-serif;
82+
height: 32px;
83+
}
84+
85+
/* Styles for the disabled button state */
86+
button:disabled {
87+
background-color: rgb(177, 177, 177); /* Gray color when disabled */
88+
border-color: rgb(177, 177, 177);
89+
}
90+
91+
/* Hover effect for the button (only when not disabled) */
92+
button:not([disabled]):hover {
93+
background-color: rgb(64, 70, 202); /* Darker blue on hover */
94+
cursor: pointer;
95+
}
96+
</style>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="description" content="Get started with Add-on development using Vue.js" />
6+
<meta name="keywords" content="Adobe, Express, Add-On, Vue.js" />
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8+
<title>Get Started with Vue</title>
9+
</head>
10+
<body>
11+
<!--
12+
This is the mounting point for our Vue application.
13+
The <div id="app"></div> element is where Vue will render everything.
14+
15+
When our index.js file runs app.mount('#app'), Vue attaches to this div
16+
and replaces its contents with the rendered components.
17+
18+
In single-page applications (SPAs) like this one, Vue manages the entire UI
19+
from this single mounting point.
20+
-->
21+
<div id="app"></div>
22+
23+
<!--
24+
The main JavaScript entry point for our application.
25+
This script is processed by webpack, which bundles all our JavaScript
26+
including Vue components into a single file.
27+
28+
The "type="module"" attribute enables ES modules syntax (import/export)
29+
in the browser.
30+
-->
31+
<script type="module" src="index.js"></script>
32+
</body>
33+
</html>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { createApp } from 'vue'
2+
import App from './App.vue'
3+
4+
// Create the app instance
5+
const app = createApp(App)
6+
7+
/**
8+
* Load the Adobe Express Add-on SDK and initialize the Vue app
9+
*
10+
* This function:
11+
* 1. Imports the Add-on SDK
12+
* 2. Waits for the SDK to be ready
13+
* 3. Makes the SDK available to all components via provide/inject
14+
* 4. Mounts the Vue app to the DOM
15+
*/
16+
const loadSdk = async () => {
17+
// Dynamically import the SDK
18+
// Using dynamic import (import()) allows loading the module at runtime
19+
const sdkModule = await import('https://new.express.adobe.com/static/add-on-sdk/sdk.js')
20+
21+
// Extract the default export which is the SDK itself
22+
const addOnUISdk = sdkModule.default
23+
24+
// Wait for the SDK to be ready before proceeding
25+
// This ensures that all SDK features are available
26+
await addOnUISdk.ready
27+
28+
// Use Vue's dependency injection system to make the SDK available to all components
29+
// This is preferred over global variables as it's more maintainable and testable
30+
app.provide('addOnUISdk', addOnUISdk)
31+
32+
// Mount the Vue app to the DOM element with id 'app'
33+
// This connects our Vue app to the HTML <div id="app"></div> in index.html
34+
app.mount('#app')
35+
}
36+
37+
// Initialize the app
38+
loadSdk()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"testId": "6c9f9198-6f36-47f0-9786-5f811002987e",
3+
"name": "Vue Starter",
4+
"version": "1.0.0",
5+
"manifestVersion": 2,
6+
"requirements": {
7+
"apps": [
8+
{
9+
"name": "Express",
10+
"apiVersion": 1
11+
}
12+
]
13+
},
14+
"entryPoints": [
15+
{
16+
"type": "panel",
17+
"id": "panel1",
18+
"main": "index.html"
19+
}
20+
]
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"compilerOptions": {
3+
"allowJs": true,
4+
"allowSyntheticDefaultImports": true,
5+
"experimentalDecorators": true,
6+
"module": "ESNext",
7+
"moduleResolution": "node",
8+
"outDir": "dist",
9+
"target": "ESNext",
10+
"useDefineForClassFields": false
11+
},
12+
"exclude": ["node_modules"],
13+
"include": ["src/**/*"]
14+
}

0 commit comments

Comments
 (0)