Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/extension-seo-url-mapping/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright (c) 2021, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

module.exports = {
extends: [require.resolve('@salesforce/pwa-kit-dev/configs/eslint')]
}
1 change: 1 addition & 0 deletions packages/extension-seo-url-mapping/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dev/
5 changes: 5 additions & 0 deletions packages/extension-seo-url-mapping/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
coverage
dist
generator-assets
docs
vendor
7 changes: 7 additions & 0 deletions packages/extension-seo-url-mapping/.prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
printWidth: 100
singleQuote: true
semi: false
bracketSpacing: false
tabWidth: 4
arrowParens: 'always'
trailingComma: 'none'
108 changes: 108 additions & 0 deletions packages/extension-seo-url-mapping/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
:loudspeaker: Hey there, Salesforce Commerce Cloud community!

We’re excited to hear your thoughts on your developer experience with PWA Kit and the Composable Storefront generally! Your feedback is incredibly valuable in helping us guide our roadmap and improve our offering.

:clipboard: Take our quick survey here: [Survey](https://forms.gle/bUZNxQ3QKUcrjhV18)

Feel free to share this survey link with your colleagues, partners, or anyone who has experience with PWA Kit. Your input will help us shape the future of our development tools.

Thank you for being a part of our community and for your continuous support! :raised_hands:

# Description

This is a sample PWA-Kit Application Extension. The purpose of this application extensions is to show how
the Application Extensions API can be used to enhance your PWA-Kit base project.

# Folder Structure

This directory contains the PWA Kit Application Extension base files and structure. It includes the following files:
```
├── src
│ ├── setup-server.ts
│ └── setup-client.ts
└── dev
```

1. `src/setup-server.ts`: The server-side setup function for the extension.
2. `src/setup-client.ts`: The client-side setup function for the extension.
3. `dev/`: PWA Kit App TypeScript template project used for developing the generated PWA Kit App Extension.

# Peer Dependencies

PWA-Kit Application Extensions are NPM packages at their most simplest form, and as such you can define
what peer dependencies are required when using it. Because this sample application extension provides
UI via a new "Sample" page, it requires that the below dependencies are installed at a minimum.

Depending on what features your application extensions provides it's recommended you include any third-party
packages as peer dependencies so that your base application doesn't end up having multiple versions of a
given package.

"react": "^18.2.0",
"react-dom": "^18.2.0"

# Configuration

This section is optional and will depend on your application extensions implementation. If you have features
that are configurable, then list those configurations here so that the PWA-Kit project implementor can configure
the extension as they like.

```
{
path: '/sample-page'
}
```

# Installation

```
> npm install @salesforce/extension-starter<br/>
> Downloading npm package... <br/>
> Installing extension... <br/>
> Finished. <br/>
> Congratulations! The Sample extension was successfully installed! Please visit https://www.npmjs.com/package/@salesforce/extension-starter for more information on how to use this extension.
```

# State Management

By default all extensions are enhanced with state management using the `withApplicationExtensionStore` higher-order component. Under the hood
the state is provided using [Zustand](https://www.npmjs.com/package/zustand) as a global store for the entire PWA-Kit application.
Each Application Extension inserts a "slice" into this global store following the
[slicing pattern](https://github.com/pmndrs/zustand/blob/37e1e3f193a5e5dec6fbd0f07514aec59a187e01/docs/guides/slices-pattern.md).
This allows you to have data separation from one extension to the other, but also allows you to access state and associated actions of other extensions when needed.

You can access the state of other extensions via the global store. Below is an example of why you might want to access state and actions from another extensions. In the following snippet we use the global store to access actions from the store locator. You can then use these actions as you please.

This is how you would do something like this.

```
// /base-project/app/components/my-component.jsx
import {useApplicationExtensionsStore} from '@salesforce/pwa-kit-extension-sdk/react'

export MyComponent = () => {
// Zustand V5 requires stable selector outputs. E.g. Do NOT return a new reference in your selectors return value. This will
// cause infinite re-renders.
const defaultState = {}

// Grab the slice of the extension state for "extension-a"
const {toggleMapsModal} = useApplicationExtensionsStore(
(state) =>
state.state['@salesforce/extension-store-locator'] || defaultState
)

return (
<div>
<button onClick={() => toggleMapsModal()}/>
</div>
)
}
```

# Advanced Usage

As an application extension developer you are responsible for documenting how your extension works including basic usage, its configuration, and advanced customization via overrides. Use this section to explain how your extension can use overrides to accomplish this. Make should to include what files are overridable as well as their expected inputs and outputs.

## Overridable Files

```
/src/path/to/overridable/files.ts
```
89 changes: 89 additions & 0 deletions packages/extension-seo-url-mapping/config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Extension Configuration 🧩

In most cases it's beneficial to make your application extension configurable. This will allow your extension to meet the needs of different PWA-Kit developers whom have varying requirements. This can be as simple as configuring the url path to the page your extension adds, to more complex scenarios like configuring layouts to those same pages.


## `Sample` vs `Default` Configurations

This folder is home to two configuration files, `default.json` and `sample.json`. Both of which have their type define in the `src/types/config` file. But these files are used differently. Below is a summary of how each file is used.

### `default.json`

This configuration is used during the project generation as well as the extensions loading phase when running your PWA-Kit application.

During your PWA-Kit project generation, you can select which extensions are configured for your app. This ultimately leads to your applications configuration being setup with the extensions selected during the project questionnaire phase. For example, if you were to choose to use `@salesforce/extension-chakra-storefront` in your PWA-Kit app, then you might see something along the lines of this in your app config, where `<user_defined_configuration>` is initially set to the contents of the `default.json` file:

```
app: {
extensions: [
['@salesforce/extension-chakra-storefront', <user_defined_configuration>]
]
}
```

Additionally, during the PWA-Kit application execution the default configuration is merged with the user define configuration to ensure that all configuration key have a value. This means that you do not have to worry about scattering default values in your extensions code, whether it's in a React component or the setup files.

It's worth noting that if your configuration file is expected to have values supplied by the PWA-Kit application developer, you can use placeholder values that will prompt the developer to replace them with real world values. Below is an example default config file with a placeholder:

```
{
"enabled": true,
"activeDataEnabled": false,
"categoryNav": {
"defaultNavSsrDepth": 1,
"defaultRootCategory": "root"
},
"commerceAPI": {
"proxyPath": "/mobify/proxy/api",
"parameters": {
"clientId": "<CLIENT_ID>",
"organizationId": "<ORGANIZATION_ID>",
"shortCode": "<SHORT_CODE>",
"siteId": "<SITE_ID>"
}
},
...
}
```

### `sample.json`

This configuration is similar in many ways to the one above, with the primary difference being that you cannot use placeholder values in it. The configuration is expected to have all its properties defined with valid values.

This configuration file is used internally by the PWA-Kit create-app application whenever a project is generated using a preset. This allows us to create E2E tests on our CI environment where we know that a project generated can be run without further modification to the configuration file.

We also recommend that you reference this configuration file from your extensions root README so that developers know what a valid configuration looks like.

## How to use your extension configuration?

Your extensions configuration can be used in different ways depending on the context in which you want to use it. Your configuration will primarily be used in two places, your React components and your extension setup files.

### Setup Files

The exported extension classes in `setup-app.ts` and `setup-server.ts` are extended from the `ApplicationExtension` class. This class provide a method called `getConfig` which returns the configuration your extension was instantiated with. you can use this method to grab the configuration and use it however you want.

Please refer to the `src/setup-app.ts` file to see a sample of how it's being used in the `extendRoutes` implementation.

### React Components

Every application extension generated will have a convenience hook scaffolded for you located at `src/hooks/use-extension-config`. You can use this hook in any pages, components, or other hooks that you add to your extension. Below is an example component that uses this hook:

```
// src/components/sample-component.tsx
import React from 'react'
import {useExtensionConfig} from '../hooks/use-extension-config'

export const Sample = (): JSX.Element => {
const {path} = useExtensionConfig()

return (
<span>{path}<span/>
)
}

export default Sample
```

### Other Contexts

If you plan on using the extension configuration in other contexts such as utility files, we recommend that you use dependency injection whenever possible. Passing in the configuration to these utilities will not only be a simple solution, but it will also make testing these utilities easier if you choose to do that.
4 changes: 4 additions & 0 deletions packages/extension-seo-url-mapping/config/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"enabled": true,
"path": "/sample-page"
}
9 changes: 9 additions & 0 deletions packages/extension-seo-url-mapping/dev/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
build
coverage
docs
app/static
app/application-extensions
jest.config.js
webpack
scripts/generator/assets
dist
10 changes: 10 additions & 0 deletions packages/extension-seo-url-mapping/dev/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright (c) 2021, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

module.exports = {
extends: [require.resolve('@salesforce/pwa-kit-dev/configs/eslint')]
}
11 changes: 11 additions & 0 deletions packages/extension-seo-url-mapping/dev/.force_overrides
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// DISCLAIMER
//
// BY USING THIS FILE, YOU AGREE THAT THE FUNCTIONALITY OF YOUR INSTALLED EXTENSION(S) IS NOT GUARANTEED.
// ADDITIONALLY UPGRADABILITY OF EXTENSIONS CAN ALSO NO LONGER BE GUARANTEED AND IS NOT SUPPORTED BY SALESFORCE.
// USE ONLY AS A TEMPORARY SOLUTION TO URGENTLY PATCH/UPDATE AN EXTENSION.
//
// USAGE:
// PLACE THE RELATIVE __POSIX__ PATH TO THE EXTENSION FILE YOU WANT TO OVERRIDE STARTING WITH THE EXTENSION PACKAGE NAME.
// MULTIPLE OVERRIDES CAN BE ADDED TO THIS FILE, ONE PER LINE.\
// EXAMPLE:
// ./node_modules/@salesforce/extension-sample/src/pages/home.tsx
3 changes: 3 additions & 0 deletions packages/extension-seo-url-mapping/dev/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build.tar
node_modules/
build/
7 changes: 7 additions & 0 deletions packages/extension-seo-url-mapping/dev/.prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
printWidth: 100
singleQuote: true
semi: false
bracketSpacing: false
tabWidth: 4
arrowParens: 'always'
trailingComma: 'none'
30 changes: 30 additions & 0 deletions packages/extension-seo-url-mapping/dev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Typescript Minimal

A zero-configuration project template for TypeScript applications
built with PWA Kit SDKs.

## Setup

```bash
npm ci
npm start
npm run push
```

## Documentation

The full documentation for PWA Kit is hosted on the [Salesforce Developers](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/overview) portal.

### Useful Links:

- [Get Started](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/getting-started.html)
- [Skills for Success](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/skills-for-success.html)
- [Set Up API Access](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/setting-up-api-access.html)
- [Configuration Options](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/configuration-options.html)
- [Proxy Requests](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/proxying-requests.html)
- [Push and Deploy Bundles](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/pushing-and-deploying-bundles.html)
- [The Retail React App](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/retail-react-app.html)
- [Rendering](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/rendering.html)
- [Routing](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/routing.html)
- [Phased Headless Rollouts](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/phased-headless-rollouts.html)
- [Launch Your Storefront](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/launching-your-storefront.html)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2024, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import {withLegacyGetProps} from '@salesforce/pwa-kit-react-sdk/ssr/universal/components/with-legacy-get-props'
import {withReactQuery} from '@salesforce/pwa-kit-react-sdk/ssr/universal/components/with-react-query'
import AppConfig from '@salesforce/pwa-kit-react-sdk/ssr/universal/components/_app-config'

const isServerSide = typeof window === 'undefined'

// Recommended settings for PWA-Kit usages.
// NOTE: they will be applied on both server and client side.
const options = {
queryClientConfig: {
defaultOptions: {
queries: {
retry: false,
staleTime: 2 * 1000,
...(isServerSide ? {retryOnMount: false} : {})
},
mutations: {
retry: false
}
}
}
}

export default withReactQuery(withLegacyGetProps(AppConfig), options)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2023, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import React from 'react'

const HelloJS = () => {
return <span>This is a JS component.</span>
}

export default HelloJS
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2023, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import React from 'react'

interface Props {
message: string
}

const HelloTS = ({message}: Props) => {
return <span>And this is a TS component (it takes a prop: &quot;{message}&quot;).</span>
}

export default HelloTS
9 changes: 9 additions & 0 deletions packages/extension-seo-url-mapping/dev/app/main.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (c) 2023, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
test('basic test', () => {
expect(1 + 1).toBe(2)
})
9 changes: 9 additions & 0 deletions packages/extension-seo-url-mapping/dev/app/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (c) 2023, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import {start} from '@salesforce/pwa-kit-react-sdk/ssr/browser/main'

start()
Loading
Loading