Bùi Văn Mạnh

Vue 3 + TypeScript + Vite

1 - Create UI

npm i -g bun
bun create vite --template vue-ts my-vue-app

cd my-vue-app
bun i -f

git init --initial-branch=main
git config user.name vite
git config user.email vite@setup.md

bun add --dev husky prettier
bunx husky init
echo '# .husky/pre-commit
prettier $(git diff --cached --name-only --diff-filter=ACMR | sed '"'s| |\\\\ |g'"') --write --ignore-unknown
git update-index --again' | tee .husky/pre-commit

echo 'bun.lock' >> .gitignore
git add .
git commit -m "Keep calm and commit"

2 - Add config basicSsl vite.config.ts

/* eslint-disable @typescript-eslint/ban-ts-comment */
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
import basicSsl from "@vitejs/plugin-basic-ssl";

const server = "http://server.api:8080";
const files = "http://server.api:8080";

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue({
      template: {
        compilerOptions: {
          isCustomElement: (tag) =>
            ["ui-", "s-"].some((prefix) => tag.startsWith(prefix)),
        },
      },
    }),
    basicSsl(),
  ],
  resolve: {
    tsconfigPaths: true,
    alias: {
      "@res": path.resolve(__dirname, "res"),
      "@src": path.resolve(__dirname, "src"),
      "@assets": path.resolve(__dirname, "src/assets"),
      "@components": path.resolve(__dirname, "src/components"),
    },
  },
  server: {
    // @ts-expect-error
    https: true,
    // port: 443, // default port: 5173
    proxy: { "/server/": server, "/files/": files },
  },
});

// if using port 443
// sudo setcap 'cap_net_bind_service=+ep' $(which node) # ubuntu
// prettier config: **/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,json,vue,astro,html,md}

3 - Add package @vitejs/plugin-basic-ssl

bun i -D @vitejs/plugin-basic-ssl

4 - Add config index.html: shopify-api-key, app-bridge, polaris

<head>
  ...
  <meta name="shopify-api-key" content="fbc72a9f43e4c56cd441b8011462cf6b" />
  <script src="https://cdn.shopify.com/shopifycloud/app-bridge.js"></script>
</head>

5 - Edit: src/App.vue

<script setup lang="ts">
import HelloWorld from "@components/HelloWorld.vue";
</script>

<template>
  <HelloWorld />
</template>

6 - Add Config ui-save-bar: src/components/HelloWorld.vue

<script setup lang="ts">
import { ref } from "vue";
import viteLogo from "@assets/vite.svg";
import heroImg from "@assets/hero.png";
import vueLogo from "@assets/vue.svg";

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const shopify = (window as any).shopify || {
  toast: {
    show: () => {},
    hide: () => {},
  },
};

const inputValue = ref("");

const mySaveBar = ref();
const hasUnsavedChanges = ref<boolean>(false);

const handleFieldInput = (e: any) => {
  inputValue.value = e.currentTarget?.value || "";

  shopify.toast.hide();
  if (!hasUnsavedChanges.value) {
    hasUnsavedChanges.value = true;
    mySaveBar.value.show?.();
  }
};

const handleDiscard = (e: Event) => {
  e.preventDefault();
  inputValue.value = "";

  hasUnsavedChanges.value = false;
  mySaveBar.value.hide?.();
  shopify.toast.hide();
};

const handleSave = async (e: Event) => {
  e.preventDefault();
  // Save to your backend
  await sleep(100);
  shopify.toast.show("Successfully saved!");

  hasUnsavedChanges.value = false;
  mySaveBar.value.hide?.();
};
</script>

<template>
  <ui-save-bar ref="mySaveBar">
    <button variant="primary" v-on:click="handleSave"></button>
    <button v-on:click="handleDiscard"></button>
  </ui-save-bar>

  <div class="ticks"></div>

  <section id="center">
    <div class="hero">
      <img :src="heroImg" class="base" width="170" height="179" alt="" />
      <img :src="vueLogo" class="framework" alt="Vue logo" />
      <img :src="viteLogo" class="vite" alt="Vite logo" />
    </div>

    <form v-on:submit="handleSave" v-on:reset="handleDiscard">
      <div class="hero">
        <label>
          Name:
          <input :value="inputValue" v-on:input="handleFieldInput" />
        </label>
      </div>

      <div class="hero">
        <button type="submit" class="counter">Submit</button>
        <button type="reset" class="counter">Reset</button>
      </div>
    </form>
  </section>

  <div class="ticks"></div>
</template>

7 - Commit app config

git config user.name myapp
git config user.email myapp@shopify.app

git add .
git commit -m "Add config ssl, shopify-api-key, app-bridge, ui-save-bar"

8 - Run bun dev: