diff --git a/docs/vue/release-checklist.md b/docs/vue/release-checklist.md index fa2a2c2..3ced72d 100644 --- a/docs/vue/release-checklist.md +++ b/docs/vue/release-checklist.md @@ -7,6 +7,7 @@ ```bash npm run build npm run test:vue-adapter +npm run test:vue-package ``` Expected Vite warnings: @@ -19,6 +20,12 @@ ## Pack Validation +The package smoke script automates this section: + +```bash +npm run test:vue-package +``` + Create a package tarball: ```bash diff --git a/package.json b/package.json index b6bea4a..0b7fcc4 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "build:vue": "gulp vue", "dev": "gulp serve", "start": "gulp serve", - "test:vue-adapter": "npm run build:vue && npm run build:example:vue" + "test:vue-adapter": "npm run build:vue && npm run build:example:vue", + "test:vue-package": "node scripts/vue-package-smoke.mjs" }, "peerDependencies": { "vue": "^3.4.0" diff --git a/scripts/vue-package-smoke.mjs b/scripts/vue-package-smoke.mjs new file mode 100644 index 0000000..b29795c --- /dev/null +++ b/scripts/vue-package-smoke.mjs @@ -0,0 +1,139 @@ +import { mkdtempSync, rmSync, writeFileSync, mkdirSync, readFileSync, symlinkSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { spawnSync } from "node:child_process"; + +const root = new URL("..", import.meta.url).pathname; +const workdir = mkdtempSync(join(tmpdir(), "gnexus-ui-kit-vue-pack-")); +const appdir = join(workdir, "consumer"); +const npmCache = join(workdir, "npm-cache"); +const exampleNodeModules = join(root, "examples/vue/node_modules"); +const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); + +function run(command, args, options = {}) { + const result = spawnSync(command, args, { + cwd: options.cwd || root, + env: { + ...process.env, + npm_config_cache: npmCache + }, + stdio: "inherit", + shell: false + }); + + if (result.status !== 0) { + throw new Error(`${command} ${args.join(" ")} failed`); + } +} + +function writeConsumerApp(tarball) { + mkdirSync(join(appdir, "src"), { recursive: true }); + mkdirSync(join(appdir, "node_modules/gnexus-ui-kit"), { recursive: true }); + + writeFileSync( + join(appdir, "package.json"), + `${JSON.stringify( + { + private: true, + type: "module", + scripts: { + build: "vite build" + }, + dependencies: { + "gnexus-ui-kit": `file:${tarball}`, + vue: "^3.5.22" + }, + devDependencies: {} + }, + null, + 2 + )}\n` + ); + + writeFileSync( + join(appdir, "index.html"), + ` + + + + + GNexus Vue Package Smoke + + +
+ + + +` + ); + + writeFileSync( + join(appdir, "src/main.js"), + `import { createApp, ref } from "vue"; +import "gnexus-ui-kit/dist/css/kit.css"; +import "gnexus-ui-kit/dist/assets/fonts/phosphor-icons/src/css/icons.css"; +import { GnButton, GnInput, GnModal, GnTabs, GnToastProvider, useToast } from "gnexus-ui-kit/vue"; + +const SmokeScreen = { + components: { GnButton, GnInput, GnModal, GnTabs }, + setup() { + const open = ref(false); + const name = ref("GNexus"); + const tab = ref("one"); + const toast = useToast(); + const tabs = [ + { id: "one", label: "One" }, + { id: "two", label: "Two" } + ]; + + function showToast() { + toast.success({ title: "Ready", text: name.value }); + } + + return { open, name, tab, tabs, showToast }; + }, + template: \` +
+ + + + + + Toast + Modal + + Imported from tarball. + +
+ \` +}; + +createApp({ + components: { GnToastProvider, SmokeScreen }, + template: \` + + + + \` +}).mount("#app"); +` + ); +} + +function installPackedKit(tarball) { + run("tar", ["-xzf", tarball, "--strip-components=1", "-C", join(appdir, "node_modules/gnexus-ui-kit")]); + symlinkSync(join(exampleNodeModules, "vue"), join(appdir, "node_modules/vue"), "dir"); +} + +try { + run("npm", ["run", "build"]); + run("npm", ["pack", "--pack-destination", workdir]); + + const tarball = join(workdir, `gnexus-ui-kit-${packageJson.version}.tgz`); + writeConsumerApp(tarball); + installPackedKit(tarball); + + run("node", [join(exampleNodeModules, "vite/bin/vite.js"), "build"], { cwd: appdir }); +} finally { + rmSync(workdir, { recursive: true, force: true }); +}