Skip to content

Commit

Permalink
feat(UST-1087): create package
Browse files Browse the repository at this point in the history
  • Loading branch information
jagoral committed Dec 13, 2023
1 parent ee234d8 commit 5263672
Show file tree
Hide file tree
Showing 33 changed files with 5,435 additions and 123 deletions.
5 changes: 5 additions & 0 deletions .changeset/brown-clouds-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@vue-storefront/nuxt": major
---

A new version of @vue-storefront/nuxt dedicated for Vue Storefront 2
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
**/node_modules/**/*
**/lib/*
**/dist/**/*
!**/.vuepress/**/*
packages/cache/nuxt/plugin.js
packages/nuxt-module/plugins/i18n-cookies.js
packages/nuxt-module/plugins/logger.js
packages/cli/dist
packages/middleware/__tests__/unit/test-data/*
packages/middleware/__tests__/unit/test-data/*
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ lerna-debug.log*

# Rollup generate output
lib
dist

# Coverage directory used by tools like istanbul
coverage
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@vue-storefront/jest-config": "^0.0.3",
"@vue-storefront/rollup-config": "^0.0.6",
"cross-env": "^6.0.3",
"cypress": "^13.6.1",
"husky": "^8.0.3",
"jest": "^27.0.6",
"lerna": "^6.6.2",
Expand Down
1 change: 1 addition & 0 deletions packages/nuxt/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
90 changes: 90 additions & 0 deletions packages/nuxt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# @vue-storefront/sdk-nuxt

## Quick Setup

1. Add `@vue-storefront/sdk-nuxt` dependency to your project

```bash
# Using pnpm
pnpm add -D @vue-storefront/sdk-nuxt

# Using yarn
yarn add --dev @vue-storefront/sdk-nuxt

# Using npm
npm install --save-dev @vue-storefront/sdk-nuxt
```

2. Add `@vue-storefront/sdk-nuxt` to the `modules` section of `nuxt.config.ts`

```js
export default defineNuxtConfig({
modules: ["@vue-storefront/sdk-nuxt"],
});
```

3. Configure the module

There are two ways you can configure the SDK module. The first is by using the `vsfSdk` key in the Nuxt configuration object and providing necessary information such as the Middleware instance address:

```ts
export default defineNuxtConfig({
modules: ["@vue-storefront/sdk-nuxt"],
vsfSdk: {
apiBaseUrl: "localhost:4000",
apiProtocol: "http",
apiSubpath: "",
isMultistoreEnabled: false,
},
});
```

The second is to use Runtime Config. You can set the same set of variables in Runtime Config, providing access to this data throughout the application. You can control the values of these variables through environment variables:

```ts
export default defineNuxtConfig({
modules: ["@vue-storefront/sdk-nuxt"],
runtimeConfig: {
public: {
apiBaseUrl: "localhost:4000",
},
},
});
```

4. Create SDK config file - `sdk.config.ts` in root directory of your project:

The `defineSdkConfig` function is used for this purpose. The parameter for calling this function should be an anonymous function that receives an injected context from the module, containing:

- the `buildModule` function,
- the middleware URL (`middlewareUrl`),
- a function for retrieving the Set-Cookie header with cookie values (`getCookieHeader`).
- a function that compose Middleware URL - in case you want to do it by yourself (`composeMiddlewareUrl`)
- a module config

You should import all other SDK configuration components. See the example below illustrating the SDK configuration with Unified and Contentful modules.

```ts
import {
contentfulModule,
ContentfulModuleType,
} from "@vsf-enterprise/contentful-sdk";
import { unifiedModule } from "@vsf-enterprise/unified-sdk";
import type { UnifiedApiExtension } from "../storefront-middleware/middleware.config";

export default defineSdkConfig(
({ buildModule, middlewareUrl, getCookieHeader }) => ({
unified: buildModule(unifiedModule<UnifiedApiExtension>, {
apiUrl: middlewareUrl + "/commerce",
requestOptions: {
headers: getCookieHeader,
},
}),
contentful: buildModule<ContentfulModuleType>(contentfulModule, {
apiUrl: middlewareUrl + "/cntf",
}),
}),
);
```

That's it! You can now use VueStorefront SDK in your Nuxt app ✨
21 changes: 21 additions & 0 deletions packages/nuxt/__tests__/app/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<div>
<strong>Success</strong>
<div id="result" class="mt-4">
{{ result }}
</div>
</div>
</template>

<script setup>
const sdk = useSdk();
const result = ref("null");
async function testCall() {
const data = await sdk.example.getSuccess();
result.value = JSON.stringify(data);
}
await testCall();
</script>
9 changes: 9 additions & 0 deletions packages/nuxt/__tests__/app/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default defineNuxtConfig({
modules: ["../../src/module.ts"],
vsfSdk: {
apiBaseUrl: "localhost:4000",
apiProtocol: "http",
apiSubpath: "",
isMultistoreEnabled: false,
},
});
13 changes: 13 additions & 0 deletions packages/nuxt/__tests__/app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"private": true,
"name": "@vue-storefront/nuxt-tests-app",
"type": "module",
"scripts": {
"dev": "nuxt dev",
"postinstall": "nuxt prepare"
},
"devDependencies": {
"nuxt": "3.7.4",
"@vue-storefront/sdk": "*"
}
}
8 changes: 8 additions & 0 deletions packages/nuxt/__tests__/app/sdk.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// eslint-disable-next-line import/no-relative-packages
import { exampleSdkModule } from "../sdk";

export default defineSdkConfig(({ buildModule, middlewareUrl }) => ({
example: buildModule(exampleSdkModule, {
apiUrl: `${middlewareUrl}/test_integration`,
}),
}));
3 changes: 3 additions & 0 deletions packages/nuxt/__tests__/app/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "./.nuxt/tsconfig.json"
}
13 changes: 13 additions & 0 deletions packages/nuxt/__tests__/e2e/e2e/sdkModule.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
describe("SDK Module Acceptance Criteria", () => {
beforeEach(() => {
cy.visit("http://localhost:3000");
});

it("should have meta tag on ssr rendered page", () => {
cy.get("head meta[name=generator]").should(
"have.attr",
"content",
"vue storefront 2"
);
});
});
37 changes: 37 additions & 0 deletions packages/nuxt/__tests__/e2e/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
20 changes: 20 additions & 0 deletions packages/nuxt/__tests__/e2e/support/e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import "./commands";

// Alternatively you can use CommonJS syntax:
// require('./commands')
10 changes: 10 additions & 0 deletions packages/nuxt/__tests__/middleware/middleware.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { MiddlewareConfig } from "@vue-storefront/middleware";

export default {
integrations: {
test_integration: {
location: "../../../middleware/__tests__/integration/bootstrap/server",
configuration: {},
},
},
} satisfies MiddlewareConfig;
5 changes: 5 additions & 0 deletions packages/nuxt/__tests__/middleware/nodemon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"watch": ["**/*"],
"ext": "ts",
"exec": "ts-node-dev src/index.ts"
}
14 changes: 14 additions & 0 deletions packages/nuxt/__tests__/middleware/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"private": true,
"name": "@vue-storefront/nuxt-tests-middleware",
"scripts": {
"dev": "nodemon"
},
"devDependencies": {
"@types/express": "^4.17.13",
"@vue-storefront/middleware": "*",
"express": "^4.18.1",
"nodemon": "^3.0.1",
"ts-node-dev": "^2.0.0"
}
}
11 changes: 11 additions & 0 deletions packages/nuxt/__tests__/middleware/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createServer } from "@vue-storefront/middleware";
import config from "../middleware.config";

const port = 4000;

(async () => {
const server = await createServer(config);
server.listen(port, "", () => {
console.log(`[test-middleware] API server listening on port ${port}`);
});
})();
5 changes: 5 additions & 0 deletions packages/nuxt/__tests__/middleware/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"compilerOptions": {},
"include": ["**/*.ts"],
"exclude": ["dist", "lib", "node_modules", ".turbo"]
}
19 changes: 19 additions & 0 deletions packages/nuxt/__tests__/sdk/exampleSdkModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Module } from "@vue-storefront/sdk";

interface Options {
apiUrl: string;
}

export function exampleSdkModule({ apiUrl }: Options) {
return {
connector: {
getSuccess() {
return fetch(`${apiUrl}/success`, { method: "POST" }).then((res) =>
res.json()
);
},
},
utils: {},
subscribers: {},
} satisfies Module;
}
1 change: 1 addition & 0 deletions packages/nuxt/__tests__/sdk/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./exampleSdkModule";
68 changes: 68 additions & 0 deletions packages/nuxt/__tests__/unit/composeMiddlewareUrl.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { describe, it, expect } from "vitest";
import { composeMiddlewareUrl } from "../../src/runtime/utils/composeMiddlewareUrl";

describe("SDK utils", () => {
describe("composeMiddlewareUrl", () => {
describe("single store", () => {
it("uses config values", () => {
const composedUrl = composeMiddlewareUrl({
config: {
apiBaseUrl: "localhost:8080",
apiProtocol: "https",
apiSubpath: "/api",
isMultistoreEnabled: false,
},
headers: {},
clientsideUrl: null,
});
expect(composedUrl).toBe("https://localhost:8080/api");
});
});
describe("multistore", () => {
it('uses "host" header ', () => {
const composedUrl = composeMiddlewareUrl({
config: {
apiBaseUrl: "localhost:8080",
apiProtocol: "https",
apiSubpath: "/api",
isMultistoreEnabled: true,
},
headers: {
host: "incoming-url",
},
clientsideUrl: null,
});
expect(composedUrl).toBe("https://incoming-url/api");
});
it("uses original url when request has been proxied", () => {
const composedUrl = composeMiddlewareUrl({
config: {
apiBaseUrl: "localhost:8080",
apiProtocol: "https",
apiSubpath: "/api",
isMultistoreEnabled: true,
},
headers: {
"x-forwarded-host": "original-url",
host: "proxy-url",
},
clientsideUrl: null,
});
expect(composedUrl).toBe("https://original-url/api");
});
it("uses local url when available", () => {
const composedUrl = composeMiddlewareUrl({
config: {
apiBaseUrl: "localhost:8080",
apiProtocol: "https",
apiSubpath: "/api",
isMultistoreEnabled: true,
},
headers: {},
clientsideUrl: "local-url",
});
expect(composedUrl).toBe("https://local-url/api");
});
});
});
});
Loading

0 comments on commit 5263672

Please sign in to comment.