I’ve been thinking about how to do versioning. It’s kind of tricky and we don’t know much yet, but I think we can start with this:
For each package, we need to know its Frontity dependencies. For example, a theme may be compatible with v1 of source
and v1 of router
but v2 of comments
. We need a way to let it specify that.
My proposal is to use the version in the package of each type, which is the API contract anyway. That means we can’t use @frontity/types/source
, we need a separate package with a separate version @frontity/source
.
I think this is best explained with an example.
my-theme/package.json
"types": "type.ts",
"dependencies": {
"@frontity/source": "^1.0.0",
"@frontity/router": "^1.0.0",
"@frontity/comments": "^2.0.0",
}
my-theme/type.ts
import { Action, Package } from "@frontity/types"
import Router from "@frontity/router"
import Source from "@frontity/source"
import Comments from "@frontity/comments"
interface MyTheme extends Package {
name: "my-theme";
namespaces: Namespaces<"theme">;
state: {
theme: {
prop1: number;
};
};
actions: {
theme: {
beforeSSR: Action<MyTheme>;
};
router: Router["actions"]["router"];
source: Source["actions"]["source"];
};
roots: {
theme: React.ReactType;
};
libraries: {
comments: Comments["libraries"]["comments"];
};
}
export default MyTheme
If for example my-theme can work with both router
v1 and v2 because it doesn’t use anything from v1 that has been deprecated, it can use an OR npm dependency:
my-theme/package.json
"dependencies": {
"@frontity/router": "^1.0.0 || ^2.0.0",
...
}
Now, a package implementing one specific API also needs to import a type package. For example, tiny-router
:
@frontity/tiny-router/package.json
"types": "type.ts",
"dependencies": {
"@frontity/router": "^1.0.0",
}
@frontity/tiny-router/type.ts
import { Action, Package } from "@frontity/types"
import Router from "@frontity/router"
interface TinyRouter extends Router {
name: "@frontity/tiny-router";
namespaces: Namespaces<"router">;
state: {
router: Router["state"]["router"] & {
history: string[];
};
};
actions: {
router: Router["actions"]["router"];
};
}
export default TinyRouter
Here, we need some way to know that this package implements a router. My proposal is to use a npm keyword like frontity-xxx
. For tiny-router
:
@frontity/tiny-router/package.json
"keywords": [
"frontity",
"frontity-router",
],
"dependencies": {
"@frontity/router": "^1.0.0",
}
That way we can know which package implements which API and which package only depends on what API.
We will be able to do a npm search for all available routers and:
- List them in the Frontity Admin.
- Warn the user if he is missing one package.
- Warn the user if there’s a mismatch.
- Upgrade the API for each type of package separately.
One of the less obvious parts is to figure out how to maintain different APIs where the second one is just an augmented version of the first one. In our case, the API of router
vs the API of the 3d-router
. Both need to be router
, but the first one is going to be much simpler than the second one.
We can use v1 for the router
(tiny-router
) and v2 for the context router (3d-router
).
One theme that needs contexts would need to specify it like this:
my-theme/package.json
"dependencies": {
"@frontity/router": "^2.0.0",
...
}
but an old comments package may have declared support only for v1:
my-comments/package.json
"dependencies": {
"@frontity/router": "^1.0.0",
...
}
One implementation of the v2 router, for example 3d-router
, works with both v1 and v2 so it may use this:
@frontity/3d-router/package.json
"keywords": [
"frontity",
"frontity-router"
],
"dependencies": {
"@frontity/router": "^1.0.0 || ^2.0.0",
...
}
I’m not 100% sure if this is going to work fine, but we can try.
Suggestions welcomed