Skip to main content

Developing Extensions for EverShop

EverShop extension development

info

Before you start writing code for your EverShop extension, we recommend reading the EverShop Extension Overview documentation to understand the basics of EverShop's modular architecture.

This guide will walk you through the process of setting up and developing extensions for EverShop. Extensions allow you to add new features or modify existing functionality without altering the core codebase.

This guide assumes you have already installed EverShop and have a running project. If you haven't installed EverShop yet, please refer to our installation guide.

Let's start!

Setting Up Your Development Environment

The extensions Directory

In the root folder of your EverShop project, locate or create a directory named extensions. This directory will house all the extensions for your project, including both those you develop and those you install from other sources.

If the directory doesn't exist yet, you can create it with the following command:

mkdir extensions

For more information about EverShop's project structure, refer to the architecture overview.

Configuring NPM Workspace

Extensions can have their own dependencies managed through NPM. To properly handle these dependencies, EverShop uses NPM workspaces—a feature that allows you to manage multiple packages within a single project.

To enable NPM workspaces for your extensions, add the following configuration to the package.json file in your EverShop project root:

package.json
{
"workspaces": [
"extensions/*"
]
}

With this configuration in place, running npm install will install all dependencies for your extensions, and npm will properly resolve shared dependencies across your project and its extensions.

Extension Naming Conventions

EverShop enforces specific naming conventions for extensions to ensure compatibility and avoid conflicts:

  • Use only lowercase letters [a-z] and underscores _ in extension names
  • Each extension name must be unique within your EverShop installation
  • Consider using a vendor prefix (like Vendor_ExtensionName) to prevent name collisions with other extensions

Examples of Valid Extension Names

  • freeshipping
  • vendor_freeshipping
  • my_custom_payment_method

Extension Structure

Extensions follow a structure similar to EverShop modules. A typical extension includes:

extensions
└── Vendor_ExtensionName
├── dist # This folder contains the compiled code for the extension
├── src # React components used in the extension
│ ├── api # RESTful API endpoints and middleware
│ │ └── postCreate
│ │ ├── route.json
│ │ ├── validatePostMiddleware.ts
│ │ └── [validatePostMiddleware]savePostMiddleware.ts
│ ├── graphql # GraphQL schema definitions and resolvers
│ │ └── types
│ ├── migration # Database migration scripts
│ │ └── Version_1.0.0.ts
│ ├── pages
│ │ ├── admin # Admin panel pages
│ │ │ └── postCreate
│ │ │ ├── route.json
│ │ │ ├── index.ts
│ │ │ ├── GeneralComponent.tsx
│ │ │ └── FormComponent.tsx
│ │ └── frontend # Frontend pages and components
│ │ └── postView
│ │ ├── route.json
│ │ ├── index.ts
│ │ ├── TitleComponent.tsx
│ │ ├── PriceComponent.tsx
│ │ └── VariantsComponent.tsx
│ └── bootstrap.ts
├── tsconfig.json
└── package.json # Extension dependencies

The tsconfig.json File

Each extension should include its own tsconfig.json file to configure TypeScript compilation settings. Below is an example configuration:

tsconfig.json
{
"compilerOptions": {
"module": "NodeNext",
"target": "ES2018",
"lib": ["dom", "dom.iterable", "esnext"],
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"declaration": true,
"sourceMap": true,
"allowJs": true,
"checkJs": false,
"jsx": "react",
"outDir": "./dist",
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"allowArbitraryExtensions": true,
"strictNullChecks": true,
"baseUrl": ".",
"rootDir": "src",
"paths": {
"@components/*": [
"./src/components/*",
"../../node_modules/@evershop/evershop/dist/components/*"
],
"*": ["node_modules/*"]
}
},
"include": ["src"]
}

And add a script to compile TypeScript in your package.json:

package.json
{
...
"scripts": {
"build": "tsc"
}
...
}
info

In development mode, EverShop takes care of compiling TypeScript files on the fly, so you typically don't need to manually compile them. However, each extension must be compiled to JavaScript before it can be used by EverShop in the production environment. Meaning the dist folder must exist and contain the compiled JavaScript files for the extension to function correctly in production.

warning

Do not change the name of the dist folder, as EverShop expects compiled extension code to be located there.

module type in package.json

To ensure proper module resolution, each extension's package.json file should specify the module type. Add the following field to your extension's package.json:

package.json
{
...
"type": "module",
...
}

Activating and Deactivating Extensions

After developing an extension, you need to enable it in your EverShop configuration. For example, if you've created an extension named myExtension, add the following configuration to your EverShop config file:

./config/production.json
{
...
"system": {
"extensions": [
{
"name": "myExtension",
"resolve": "extensions/myExtension",
"enabled": true,
"priority": 10 // Lower numbers indicate higher priority
}
]
}
}

To disable the extension, simply change the enabled property to false.

info

After enabling or disabling an extension, you must rebuild your project for the changes to take effect.

Publishing Your Extension as an NPM Package

While extensions can be used directly from the extensions directory, you can also publish them as NPM packages to make them easy to share and install in other EverShop projects.

Publishing Process

  1. Prepare your extension for publishing:

    • Ensure your package.json includes all necessary metadata
    • Compile your TypeScript code to JavaScript, ensuring the dist folder is up to date. Make sure to include the dist folder in your package by adding it to the files array in package.json:
    package.json
    {
    ...
    "files": [
    "dist",
    "src"
    ],
    ...
    }
    • Add appropriate documentation
    • Test your extension thoroughly
  2. Publish your package to NPM:

    npm publish --access public
  3. Install your published extension in any EverShop project:

    npm install @yournamespace/your-extension-name
  4. Configure the extension in your EverShop project:

./config/production.json
{
...
"system": {
"extensions": [
{
"name": "yourExtensionName",
"resolve": "node_modules/@yournamespace/your-extension-name",
"enabled": true,
"priority": 10
}
]
}
}
info

For a hands-on tutorial on creating your first extension, check out our Create Your First Extension guide.

Extension Development Best Practices

To ensure your extensions are maintainable, compatible, and provide the best experience for users, follow these best practices:

1. Follow EverShop Coding Standards

Maintain consistency with EverShop's core codebase by following the same coding standards and patterns. This makes your extension more intuitive for other developers familiar with EverShop.

2. Minimize Core Overrides

Avoid directly overriding core files whenever possible. Instead, use EverShop's extension points, events, and hooks to modify behavior.

3. Proper Versioning

Use semantic versioning for your extensions to clearly communicate changes:

  • Increment the major version for breaking changes
  • Increment the minor version for new features
  • Increment the patch version for bug fixes

4. Comprehensive Testing

Test your extensions thoroughly across different configurations and with other common extensions to ensure compatibility.

5. Clear Documentation

Provide clear documentation that includes:

  • Installation instructions
  • Configuration options
  • Feature descriptions
  • Any dependencies on other extensions
  • Screenshots or diagrams for complex features

6. Handle Updates Gracefully

Implement proper migration scripts for database changes and provide clear update paths between versions of your extension.

7. Error Handling

Implement robust error handling to prevent your extension from breaking the entire application if something goes wrong.