Skip to content

Commit

Permalink
Merge branch 'main' into add-line-about-required-checks
Browse files Browse the repository at this point in the history
  • Loading branch information
sushmangupta authored Jan 15, 2025
2 parents 7223a1b + d10b2da commit 98a125a
Show file tree
Hide file tree
Showing 19 changed files with 179 additions and 29 deletions.
64 changes: 64 additions & 0 deletions .github/scripts/broken-pageref.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// deno run --allow-read .github/scripts/broken-pageref.js

import { resolve, dirname, fromFileUrl } from "https://deno.land/std/path/mod.ts";
import { walk } from "https://deno.land/std/fs/mod.ts";

const rootDir = resolve(Deno.cwd());

async function findBrokenLinks() {
const brokenLinks = [];

for await (const entry of walk(rootDir, { exts: ['.md'], followSymlinks: true })) {
if (entry.isFile) {
const content = await Deno.readTextFile(entry.path);
const matches = [...content.matchAll(/<PageRef page="([^"]+)"/g)];

for (const match of matches) {
let relativePath = match[1];

if (relativePath.startsWith('http')) {
continue
}

if (relativePath.includes('#')) {
relativePath = relativePath.split('#')[0]
}

if (relativePath.endsWith('/')) {
relativePath = `${relativePath}/index.md`
}

if (relativePath.endsWith('.html')) {
relativePath = `${relativePath.substring(0, relativePath.length - '.html'.length)}.md`
} else if (!relativePath.endsWith('.md')) {
relativePath = `${relativePath}.md`
}

const resolvedPath = resolve(dirname(entry.path), relativePath);

try {
await Deno.stat(resolvedPath);
} catch {
brokenLinks.push({ file: entry.path, relativePath, resolvedPath });
}
}
}
}

return brokenLinks;
}

const brokenLinks = await findBrokenLinks();
if (brokenLinks.length) {
console.log('Broken links found:');
brokenLinks.forEach(link => {
console.log(`File: ${link.file}`);
console.log(`Relative Path: ${link.relativePath}`);
console.log(`Resolved Path: ${link.resolvedPath}`);
console.log('---');
});
Deno.exit(1)
}

console.log('No broken links found.');
Deno.exit(0)
7 changes: 7 additions & 0 deletions .github/workflows/markdown-style-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ jobs:
- name: Check out code
uses: actions/checkout@v4

- uses: denoland/setup-deno@v1
with:
deno-version: "~1.32"

- name: Check broken PageRef links
run: deno run --allow-read .github/scripts/broken-pageref.js

- name: Lint all files
uses: docker://avtodev/markdown-lint:v1.5
with:
Expand Down
2 changes: 1 addition & 1 deletion concepts/api/store-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Whenever additional logic is added to Shopware, the method of the corresponding

Using plugins, you can add custom routes to the Store API \(as well as any other routes\) and also register custom services. We don't force developers to provide API coverage for their functionalities. However, if you want to support headless applications, ensure that your plugin provides its functionalities through dedicated routes.

<PageRef page="../../guides/plugins/plugins/framework/store-api" />
<PageRef page="../../guides/plugins/plugins/framework/store-api/" />

## What next?

Expand Down
2 changes: 1 addition & 1 deletion guides/plugins/apps/content/cms/add-custom-cms-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ nav:
::: info
This functionality is available starting with Shopware 6.4.4.0.

You can [add custom CMS blocks](../../../plugins/content/cms/add-cms-block) using the plugin system, however these will not be available in Shopware cloud stores.
Alternatively, you can [add custom CMS blocks](../../../plugins/content/cms/add-cms-block) using the plugin system, however these will not be available in Shopware cloud stores.
:::

Didn't get in touch with Shopware's Shopping Experiences \(CMS\) yet? Check out the concept behind it first:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ You want to create a custom card in the rule assignment, where you can add or de
This guide **does not** explain how to create a new plugin for Shopware 6.
Head over to our Plugin base guide to learn how to create a plugin at first:

<PageRef page="../plugin-base-guide" />
<PageRef page="../../plugin-base-guide" />

## Creating the index.js file

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ Think twice about adding this shortcut because if every plugin adds their own se

For this guide, it's necessary to have a running Shopware 6 instance and full access to both the files and a running plugin. See our plugin page guide to learn how to create your own plugins.

<PageRef page="../plugin-base-guide" />
<PageRef page="../../plugin-base-guide" />

In addition, you need a custom entity to add to the search to begin with. Head over to the following guide to learn how to achieve that:

<PageRef page="../framework/data-handling/add-custom-complex-data" />
<PageRef page="../../framework/data-handling/add-custom-complex-data" />

## Support custom entity via search API

To support an entity in the untyped global search, the entity has to be defined in one of the Administration Modules.

<PageRef page="./add-custom-module.md" />
<PageRef page="../module-component-management/add-custom-module.md" />

Add the `entity` and `defaultSearchConfiguration` values to your module to make it available to the search bar component.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ nav:

All you need for this guide is a running Shopware 6 instance, the files and preferably a registered module in your own plugin. Don't know how to create an own plugin yet? Head over to the following guide:

<PageRef page="../plugin-base-guide" />
<PageRef page="../../plugin-base-guide" />

In order to craft your module, you will need to create lots on own components. If you're not sure about how to do that, take a look at the corresponding guide:

<PageRef page="add-custom-component" />
<PageRef page="../module-component-management/add-custom-component" />

In addition, of course you need an entity with custom fields to be able to add those custom fields to your module to begin with. Here you can learn how to add your custom fields:

<PageRef page="../framework/custom-field/add-custom-field" />
<PageRef page="../module-component-management/add-custom-field" />

## Using custom fields in your module

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ In this example, you will create a component that will print a 'Hello world!' ev

This guide **does not** explain how to create a new plugin for Shopware 6. Head over to our Plugin base guide to learn how to create a plugin at first:

<PageRef page="../plugin-base-guide" />
<PageRef page="../../plugin-base-guide" />

If you want to work with entities in your custom component or page, it might be useful to take a look at how to create a custom entity guide first:

<PageRef page="../framework/data-handling/add-custom-complex-data" />
<PageRef page="../../framework/data-handling/add-custom-complex-data" />

Especially if you want to add a new page for an own module, you should consider looking at the process on how to add a custom module first.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ If you were wondering how to add a new input field to an existing module in the

This guide **does not** explain how you can create a new plugin for Shopware 6. Head over to our plugin base guide to learn how to create a plugin at first:

<PageRef page="../plugin-base-guide" />
<PageRef page="../../plugin-base-guide" />

## Injecting into the Administration

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Inside the `module` directory lies the list of several modules, each having thei
This guide **does not** explain how to create a new plugin for Shopware 6.
Head over to our Plugin base guide to learn how to create a plugin at first:

<PageRef page="../plugin-base-guide" />
<PageRef page="../../plugin-base-guide" />

## Creating the index.js file

Expand Down Expand Up @@ -69,7 +69,7 @@ In our case here, let's say we use the icon `default-shopping-paper-bag-product`

::: danger
This is not the icon being used for a menu entry! The icon for that needs to be configured separately.
Please refer to the [Add a menu entry](add-menu-entry) guide for more information on this topic.
Please refer to the [Add a menu entry](../routing-navigation/add-menu-entry) guide for more information on this topic.
:::

In addition, you're able to configure a title here, which will be used for the actual browser title.
Expand All @@ -87,11 +87,11 @@ Those routes are configured as an object in a property named `routes`. We will c

The next steps are covered in their own guides. The first one would be adding a menu entry, so please take a look at the guide regarding:

<PageRef page="add-menu-entry" />
<PageRef page="../routing-navigation/add-menu-entry" />

The second one refers to setting up custom routes, its guide can be found in the guide on adding custom routes:

<PageRef page="add-custom-route" />
<PageRef page="../routing-navigation/add-custom-route" />

## Set up additional meta info

Expand Down Expand Up @@ -299,8 +299,8 @@ In addition, you surely want to customize your module even more.
You may want to try the following things:
* [Add custom component](add-custom-component)
* [Add a menu entry](add-menu-entry)
* [Add a custom route](add-custom-route)
* [Add a menu entry](../routing-navigation/add-menu-entry)
* [Add a custom route](../routing-navigation/add-custom-route)
* [Add a custom service](add-custom-service)
* [Add translations](adding-snippets)
* [Customizing another module](customizing-modules)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ When it comes to the module configuration, the menu entry is one of the most imp

This guide **does not** explain how to create a new plugin for Shopware 6. Head over to our Plugin base guide to learn how to create a plugin at first:

<PageRef page="../plugin-base-guide" />
<PageRef page="../../plugin-base-guide" />

Especially if you want to add a new page for an own module, you should consider to look at the process on how to add a custom module first.

<PageRef page="add-custom-module" />
<PageRef page="../module-component-management/add-custom-module" />

## Creating a simple menu entry

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ You want to create a new tab in the Administration? This guide gets you covered

This guide requires you to already have a basic plugin running. If you don't know how to do this in the first place, have a look at our plugin base guide:

<PageRef page="../plugin-base-guide" />
<PageRef page="../../plugin-base-guide" />

In the course of this guide, you need to create a custom route. If you want to learn on how to create a custom component, please refer to the guide on it:

<PageRef page="add-custom-route" />

Also, we will use a small, custom component to fill our custom tab. In order to get used to that, it might come in handy to read the corresponding guide first:

<PageRef page="add-custom-component" />
<PageRef page="../module-component-management/add-custom-component" />

::: info

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ All components contain own templates and some style. Of course, you may want to

However, this guide does not explain how to create a custom component, so head over to the official guide about creating a custom component to learn this first.

<PageRef page="add-custom-component" />
<PageRef page="../module-component-management/add-custom-component" />

In addition, you need to have a basic knowledge of CSS and SCSS in order to use custom styles. This is though considered a basic requirement and won't be taught in this guide.

### Example: Custom cms block

We will base our guide on an example: Let's use a custom component printing out "Hello world!". So first of all, create a new directory for your`sw-hello-world`. As said before, more information about that topic, such as where to create this directory, can be found in [Add a custom component](add-custom-component).
We will base our guide on an example: Let's use a custom component printing out "Hello world!". So first of all, create a new directory for your`sw-hello-world`. As said before, more information about that topic, such as where to create this directory, can be found in [Add a custom component](../module-component-management/add-custom-component).

In your component's directory, create a new `index.js` file and register your custom component `sw-hello-world`:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ When working with an own plugin, the usage of own custom images or other assets

In order to be able to start with this guide, you need to have an own plugin running. As to most guides, this guide is also built upon the Plugin base guide:

<PageRef page="../plugin-base-guide" />
<PageRef page="../../plugin-base-guide" />

Needless to say, you should have your image or another asset at hand to work with.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ nav:

The Shopware 6 Administration provides two ways of adding classes to elements based on their size, the device helper and the `v-responsive` directive. Alternatively you can use `css` media queries to make your plugin responsive. Learn how to use `css` here:

<PageRef page="add-custom-styles" />
<PageRef page="../templates-styling/add-custom-styles" />

## DeviceHelper

Expand Down
2 changes: 1 addition & 1 deletion guides/plugins/plugins/content/cms/add-cms-element.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ You won't learn how to create a plugin in this guide, head over to our Plugin ba

This guide will also not explain how a custom component can be created in general, so head over to the official guide about creating a custom component to learn this first.

<PageRef page="../../administration/add-custom-component" />
<PageRef page="../../administration/module-component-management/add-custom-component" />

## Creating your custom element

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ To update or delete a `custom_field_set`, you can use the standard repository me

While theoretically your custom field is now properly defined for the Administration, you'll still have to do some work in your custom entities' Administration module. Head over to this guide to learn how to add your field to the Administration:

<PageRef page="../../administration/using-custom-fields" />
<PageRef page="../../administration/data-handling-processing/using-custom-fields" />

## Next steps

Expand Down
2 changes: 1 addition & 1 deletion guides/plugins/plugins/storefront/use-media-thumbnails.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ In order to use your own media files or thumbnails of your plugin in the Storefr

Displaying custom images is often done by using custom fields. To take full advantage of this guide, you might want to read the corresponding guide on using custom fields:

<PageRef page="../administration/add-custom-field" />
<PageRef page="../administration/module-component-management/add-custom-field" />

## Using searchMedia function

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
title: Vue 2 Options API to Vue 3 Composition API Conversion Codemod
date: 2024-10-02
area: Frontend Development
tags: [vue, migration, codemod, eslint, composition-api]
---

# Vue 2 Options API to Vue 3 Composition API Conversion Codemod

::: info
This document represents an architecture decision record (ADR) and has been mirrored from the ADR section in our Shopware 6 repository.
You can find the original version [here](https://github.com/shopware/shopware/blob/trunk/adr/2024-10-02-vue-2-options-api-to-vue-3-composition-api-conversion-codemod.md)
:::

## Context

Our Vue.js application currently uses the Options API, which is the traditional way of writing Vue components in Vue 2. With the release of Vue 3, the Composition API was introduced, offering improved code organization, better TypeScript support, and enhanced reusability of component logic. For more detailed information about the reasons for migrating to the Composition API, see the [documentation entry](/docs/guides/plugins/plugins/administration/system-updates/vue-native.html).

To modernize our codebase and take advantage of these benefits, we need to migrate our existing Vue 2 Options API components to use the Vue 3 Composition API. Manual conversion of numerous components would be time-consuming and error-prone. Therefore, we need an automated solution to assist in this migration process.

## Decision

We have decided to implement a Codemod in the form of an ESLint rule to automatically convert Vue 2 Options API components to Vue 3 Composition API. This Codemod will:

1. Identify Vue component definitions in the codebase.
2. Convert the following Options API features to their Composition API equivalents:
- Convert `data` properties to `ref` or `reactive`.
- Convert `computed` properties to `computed()` functions.
- Convert `methods` to regular functions within the `setup()` function.
- Convert lifecycle hooks to their Composition API equivalents (e.g., `mounted` to `onMounted`).
- Convert Vue 2 specific lifecycle hooks to their Vue 3 equivalents.
- Convert `watch` properties to `watch()` functions.
- Handle `props` and `inject` conversions.
- Replace `this` references with direct references to reactive variables.
- Convert writable computed properties.
- Handle reactive object reassignments using `Object.assign`
- Handle correct usage of `ref` and replace the access to the value with `.value`.

3. Generate a `setup()` function containing the converted code.
4. Add necessary imports for Composition API functions (e.g., `ref`, `reactive`, `computed`, `watch`).

The Codemod will be implemented as an ESLint rule to leverage the existing ESLint ecosystem and allow for easy integration into our development workflow.

## Consequences

### Positive Consequences

1. Automated conversion will significantly reduce the time and effort required to migrate components to the Composition API.
2. Consistent conversion patterns will be applied across the codebase, ensuring uniformity.
3. The risk of human error during manual conversion is minimized.
4. Developers can gradually adopt the Composition API, as the Codemod can be run on a per-file or per-component basis.
5. The Codemod can be easily shared and used across different projects within the organization.

### Negative Consequences

1. The Codemod may not cover all edge cases or complex component structures, requiring manual intervention in some scenarios.
2. Developers will need to review and potentially refactor the converted code to ensure optimal usage of the Composition API.
3. The Codemod does not handle template changes, such as adjusting `$refs` usage.

### Limitations and Manual Steps

While the Codemod handles many aspects of the conversion, some parts will still require manual attention:

1. Template modifications: The Codemod doesn't update the component's template. Developers will need to manually adjust template bindings, event handlers, and `ref` usage.
2. Complex data structures: While simple `data` properties are converted to `ref()` or `reactive()`, more complex nested structures might require manual optimization.
3. Vuex store interactions: The Codemod doesn't automatically convert Vuex `mapState`, `mapGetters`, `mapActions`, etc. These will need to be manually converted to use the `useStore` composition function.
4. Mixins: The Codemod doesn't handle the conversion of mixins. These will need to be manually refactored into composable functions.
5. Plugin usage: Certain plugins or third-party libraries that rely on the Options API might require manual updates or replacements.
6. TypeScript annotations: If the project uses TypeScript, type annotations for props, computed properties, and methods will need to be manually added or adjusted in the `setup()` function.
7. Spread operators in computed properties: The Codemod identifies these but doesn't fully convert them. A TODO comment is added for manual attention.
8. Components using render functions or JSX will need manual conversion.
9. Performance optimizations like `shallowRef` or `shallowReactive` are not automatically applied.
10. The converted code may benefit from further refactoring to extract reusable composables.
11. Error handling and edge cases in lifecycle hooks may need manual review.
12. Usage of plugins, etc. in the `this` context may need manual conversion, e.g. `$tc`, `$t`, etc.
13. Sometimes the reassignment of reactive objects over multiple lines may not be handled correctly every time.
14. Usage of `$emit` in the Options API may need manual conversion to `defineEmits` in the Composition API and then using the `emit` function.

By implementing this Codemod, we take a significant step towards modernizing our Vue.js codebase while acknowledging that some manual work will still be required to complete the migration process.

0 comments on commit 98a125a

Please sign in to comment.