UNPKG

sfcc-dev-mcp

Version:

MCP server for Salesforce B2C Commerce Cloud development assistance including logs, debugging, and development tools

398 lines (311 loc) 12.2 kB
# Instructions for Creating a Salesforce B2C Commerce (SFRA) Cartridge This document provides instructions to create, configure, and deploy a new custom cartridge for Salesforce B2C Commerce using the Storefront Reference Architecture (SFRA). **NOTE**: When doing this, also request best practices for controller creation from this MCP server. Additionally, consult the **Performance and Stability Best Practices** guide from this MCP server to ensure your cartridge follows performance optimization strategies and coding standards. ## 1. Core Principles **Cartridge:** A cartridge is a self-contained module for code and data. It is the fundamental unit for extending functionality. **Cartridge Path:** A colon-separated list of cartridge names that dictates the order of code execution. The path is searched from left to right, and the first resource found is used. **Override Mechanism:** To customize functionality, create a new cartridge (e.g., app_custom_mybrand) and place it at the beginning of the cartridge path. This allows your custom files to override the base functionality without modifying the core app_storefront_base cartridge. **Example Path:** `app_custom_mybrand:app_storefront_base` ## 2. Prerequisites - **Git Client:** Installed and configured. - **Node.js:** Version 18 is recommended for compatibility. - **SFCC Sandbox:** Access to a sandbox instance, including Business Manager credentials. - **GitHub Access:** Ability to clone SalesforceCommerceCloud repositories. ## 3. Environment Setup Create a parent project directory. Clone the following repositories as siblings inside the parent directory: Note: This step is not necessary unless specifically asked for. You should only clone these if the user requests it, for most projects, there is only a need for the new cartridge that is being built - but not the entire storefront reference architecture. ```bash # Contains the base cartridge (app_storefront_base) git clone git@github.com:SalesforceCommerceCloud/storefront-reference-architecture.git # Contains build and deployment scripts git clone git@github.com:SalesforceCommerceCloud/sgmf-scripts.git ``` Install dependencies: ```bash cd storefront-reference-architecture npm install ``` ## 4. Cartridge File Structure A new cartridge should be created using the provided scaffolding tool. The core structure is as follows: ``` package.json .eslintrc.json .eslintignore .stylelintrc.json .gitignore README.md dw.json webpack.config.js cartridges/ └── plugin_my_custom_cartridge/ └── cartridge/ ├── client/ │ └── default/ │ ├── js/ │ └── scss/ ├── controllers/ ├── models/ ├── scripts/ └── templates/ └── default/ ``` Optional but common directories: - `cartridge/forms/default/`: XML form definitions. - `cartridge/services/`: Definitions for external web service integrations. - `cartridge/scripts/jobs/`: Scripts for automated tasks scheduled in Business Manager. - `cartridge/properties/`: Localization string files (.properties). ## 5. Creating a New Cartridge ### Step 1: Generate the Cartridge Structure !IMPORTANT!: Always do this step, don't attempt to create the cartridge structure manually. The scaffolding tool ensures all necessary files and configurations are created correctly. The `sgmf-scripts --createCartridge` command creates a complete project structure including all necessary configuration files. Run the following commands: ```bash npm install sgmf-scripts -g sgmf-scripts --createCartridge plugin_my_custom_cartridge ``` **Important**: This command creates a subdirectory named `plugin_my_custom_cartridge` containing the entire project structure, including: - `.eslintrc.json` - `.stylelintrc.json` - `dw.json` - `package.json` - `webpack.config.js` - `cartridges/` directory with the cartridge structure - Other configuration files ### Step 2: Reorganize Project Structure (Optional) If you want the project files at the root level instead of in a subdirectory, you can move all files and folders up one level: ```bash # Navigate to the created directory cd plugin_my_custom_cartridge # Move all files and folders up one level mv * ../ mv .* ../ 2>/dev/null || true # Move hidden files, ignore errors for . and .. # Navigate back to parent and remove empty directory cd .. rmdir plugin_my_custom_cartridge ``` ### Step 3: Complete the Setup with manual file creation #### .eslintignore (ESLint Ignore Configuration) ```plaintext node_modules/ cartridges/**/cartridge/static/ coverage/ doc/ bin/ codecept.conf.js ``` #### gitignore (Git Ignore Configuration) ```plaintext node_modules/ cartridges/*/cartridge/static/ coverage/ npm-debug.log cartridges.zip .idea/ dw.json sitegenesisdata/ mobilefirstdata/ storefrontdata/ demo_data_sfra/ demo_data_sfra.zip .DS_Store test/appium/webdriver/config.json .vscode .history *.iml .idea test/acceptance/report test/integration/config.json ``` **Note**: Only do this reorganization if you prefer to have the project files at the root level of your workspace. The generated structure works perfectly as-is within the subdirectory. ## 6. Configuration Files (Reference) The following configuration files are automatically generated by the scaffolding tool. You can reference these examples if you need to understand or modify the generated configurations: **Note:** The scaffolding tool creates these files automatically. Only modify them if you have specific customization needs. ### .eslintrc.json (ESLint Configuration) ```json { "root": true, "extends": [ "airbnb-base/legacy", "prettier" ], "rules": { "import/no-unresolved": "off", "indent": ["error", 4, { "SwitchCase": 1, "VariableDeclarator": 1 }], "func-names": "off", "require-jsdoc": "error", "valid-jsdoc": ["error", { "preferType": { "Boolean": "boolean", "Number": "number", "object": "Object", "String": "string" }, "requireReturn": false}], "vars-on-top": "off", "global-require": "off", "no-shadow": ["error", { "allow": ["err", "callback"]}], "max-len": "off", "no-plusplus": "off" } } ``` ### package.json (Main Configuration) ```json { "name": "plugin_my_custom_cartridge", "version": "1.0.0", "description": "A custom cartridge, for your SFRA project", "main": "index.js", "scripts": { "test": "sgmf-scripts --test test/unit/**/*.js", "lint": "sgmf-scripts --lint js", "upload": "sgmf-scripts --upload -- ", "uploadCartridge": "sgmf-scripts --uploadCartridge plugin_dynamicurl && sgmf-scripts --uploadCartridge bm_dynamicurl_sitemap", "lint:isml": "./node_modules/.bin/isml-linter", "build:isml": "./node_modules/.bin/isml-linter --build", "fix:isml": "./node_modules/.bin/isml-linter --autofix", "watch": "sgmf-scripts --watch", "prepare": "husky install" }, "devDependencies": { "app-module-path": "2.2.0", "chai": "4.3.6", "chai-subset": "1.6.0", "dw-api-mock": "git+https://bitbucket.org/theunth/dw-api-mock.git", "eslint": "8.56.0", "eslint-config-airbnb-base": "15.0.0", "eslint-plugin-import": "2.29.0", "eslint-plugin-sitegenesis": "1.0.0", "husky": "8.0.1", "isml-linter": "5.40.3", "lodash": "4.17.21", "mocha": "10.1.0", "proxyquire": "2.1.3", "sgmf-scripts": "3.0.0", "sinon": "17.0.1" }, "browserslist": [ "last 2 versions", "ie >= 10" ], "paths": { "base": "../storefront-reference-architecture/cartridges/app_storefront_base/" } } ``` ### dw.json (Deployment Credentials) This file contains sandbox credentials. It must be added to .gitignore. This file lives in the root of the project. ```json { "hostname": "your-sandbox-id.dx.commercecloud.salesforce.com", "username": "your.username@example.com", "password": "your-business-manager-password", "code-version": "sfra_dev_v1" } ``` ### webpack.config.js (Webpack Configuration) ```javascript 'use strict'; var path = require('path'); var ExtractTextPlugin = require('sgmf-scripts')['extract-text-webpack-plugin']; var sgmfScripts = require('sgmf-scripts'); module.exports = [{ mode: 'production', name: 'js', entry: sgmfScripts.createJsPath(), output: { path: path.resolve('./cartridges/plugin_my_custom_cartridge/cartridge/static'), filename: '[name].js' } }, { mode: 'none', name: 'scss', entry: sgmfScripts.createScssPath(), output: { path: path.resolve('./cartridges/plugin_my_custom_cartridge/cartridge/static'), filename: '[name].css' }, module: { rules: [{ test: /\.scss$/, use: ExtractTextPlugin.extract({ use: [{ loader: 'css-loader', options: { url: false, minimize: true } }, { loader: 'postcss-loader', options: { plugins: [ require('autoprefixer')() ] } }, { loader: 'sass-loader', options: { includePaths: [ path.resolve(process.cwd(), '../storefront-reference-architecture/node_modules/'), path.resolve(process.cwd(), '../storefront-reference-architecture/node_modules/flag-icon-css/sass') ] } }] }) }] }, plugins: [ new ExtractTextPlugin({ filename: '[name].css' }) ] }]; ``` ## 7. "Hello, World" Example ### Step 1: Navigate to Your Project After creating the cartridge structure, navigate to your project directory: ```bash # If you kept the subdirectory structure: cd plugin_my_custom_cartridge # If you moved files to root level, you're already in the right place ``` ### Step 2: Create the Controller **File:** `cartridges/plugin_my_custom_cartridge/cartridge/controllers/Hello.js` ```javascript 'use strict'; var server = require('server'); // URL: /Hello-Show server.get('Show', function (req, res, next) { res.render('hello/helloTemplate', { message: 'Hello from a custom cartridge!' }); next(); }); module.exports = server.exports(); ``` ### Step 3: Create the ISML Template **File:** `cartridges/plugin_my_custom_cartridge/cartridge/templates/default/hello/helloTemplate.isml` ```html <iscontent type="text/html" charset="UTF-8" compact="true"/> <isdecorate template="common/layout/page"> <isreplace name="main"> <div class="container"> <h1>Custom Page</h1> <p>${pdict.message}</p> </div> </isreplace> </isdecorate> ``` ### Step 4: Update Deployment Configuration Ensure your `dw.json` file has the correct sandbox credentials (this file is automatically generated but needs your specific sandbox details). ## 8. Deployment and Registration ### Step 1: Upload the Cartridge From the project root, run: ```bash npm run uploadCartridge plugin_my_custom_cartridge ``` For continuous development, use `npm run watch`. ## 9. Naming Conventions & Best Practices **Cartridge Naming:** Use standard prefixes. - `app_custom_*`: Site-specific customizations. - `int_*`: Third-party integrations. - `bm_*`: Business Manager extensions. - `plugin_*`: Reusable SFRA feature extensions. **File Naming:** Controllers use PascalCase.js. Other JS files use camelCase.js. **NEVER modify app_storefront_base or other base/plugin cartridges directly.** **Extend, Don't Replace:** Use server.append() or server.prepend() to extend controllers. Avoid server.replace(). **Logic-less Templates:** Keep business logic out of ISML files. Use models to prepare data. **Security:** Protect all state-changing POST requests with CSRF tokens. Properly encode all user-provided output to prevent XSS. **Localization:** Use Resource.msg() in templates to fetch text from .properties files.