Concepts
Concepts are at the center of Storefront X architecture. In a nutshell, concepts go through directories of enabled modules, and based on their contents, concepts generate the .sfx/
directory.
Concepts are classes that have methods which are executed before each module is loaded (before()
), once per module when that module is loaded (run(module)
) and after each module is loaded (after()
). During this lifecycle, concepts perform their "magic".
Because a lot of functionality is shared between modules, Storefront X has multiple pre-defined concept classes with common functionality. These classes also inherit from each other and this inheritance hierarchy can be seen on the diagram bellow.
IoC concept
IoC concept is the most simple and most common concept.
It requires files inside concept directories to use default export
.
Extending concept
Enables extending functionality.
More information about this functionality can be found here.
Generating concept
Generates only one file. This one generated file re-exports default exports of files inside concept directories as a single, default exported, object. This file is generated inside the .sfx/
directory and has the same name as the concept directory upon which this concept operates.
Example concept
module-a/concepts/ServerRoutes.js
import { GeneratingConcept } from '@storefront-x/core'
export default class ServerRoutes extends GeneratingConcept {
get directory() {
return 'server/routes'
}
}
Example source files
module-b/server/routes/B.ts
export default () => 'B'
module-c/server/routes/C.ts
export default () => 'C'
Example generated file
.sfx/server/routes.ts
// generated by Storefront X
import B from '~/modules/module-b/server/routes/B'
import C from '~/modules/module-v/server/routes/C'
export default {
B: B,
C: C,
}
Example usage
import serverRoutes from '~/.sfx/server/routes'
console.log(serverRoutes)
Customizing generated file
You can override the template
getter in your concept to customize how the generated file looks like. This getter returns a string which is an ejs template which has access to a records
object containing files to be generated.
Example concept
// @ts-check
import { GeneratingConcept } from '@storefront-x/core'
export default class AsyncComponents extends GeneratingConcept {
get directory() {
return 'asyncComponents'
}
get template() {
return `// generated by Storefront X
import { defineAsyncComponent } from 'vue'
export default {
<%_ for (const [ident, record] of Object.entries(records)) { _%>
'<%= ident %>': defineAsyncComponent(() => import('<%= record.path %>')),
<%_ } _%>
}
`
}
}
Example generated file
// generated by Storefront X
import { defineAsyncComponent } from 'vue'
export default {
A: defineAsyncComponent(() => import('...')),
B: defineAsyncComponent(() => import('...')),
}
Separating client/server code
Sometimes you might wish to separate client/server code. This can be done with the supportsClientServer
getter. If this getter is set to true
, generating concept will generate two files with .client
and .server
suffixes. Both of these files will contain normal source files, but .client
file will also contain source files with the .client
suffix and vice versa for server.
Example concept
import { GeneratingConcept } from '@storefront-x/core'
export default class Plugins extends GeneratingConcept {
get directory() {
return 'plugins'
}
get supportsClientServer() {
return true
}
}
Example source files
my-module/plugins/A.ts
export default () => 'common'
my-module/plugins/B.client.ts
export default () => 'client'
my-module/plugins/B.server.ts
export default () => 'server'
Example generated files
.sfx/plugins.server.ts
// generated by Storefront X
import A from '~/modules/my-module/plugins/A'
import B from '~/modules/my-module/plugins/B.server'
export default {
B: B,
C: C,
}
.sfx/plugins.client.ts
// generated by Storefront X
import A from '~/modules/my-module/plugins/A'
import B from '~/modules/my-module/plugins/B.client'
export default {
B: B,
C: C,
}
Example usage
import pluginsClient from '~/.sfx/plugins.client'
import pluginsServer from '~/.sfx/plugins.server'
console.log(pluginsClient)
console.log(pluginsServer)
Generating multiple files
Generating concept can also generate multiple files (one generated file per one source file). This can be achieved by setting the generateMultipleFiles
getter to true
. If done so, the template string will receive a record
value instead of records
.
Copying concept
Copying concept copies source files to the target directory. This is useful for implementing, for example, the Public
concept which exposes static files publicly under URL corresponding to their path/name.
Merging concept
Merging files implements overriding on the basis of objects, not files. So, two files with the same name do not override each other but instead, their default exported objects are merged together.