Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 1.7.0 #721

Merged
merged 13 commits into from
Oct 16, 2024
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Piral Changelog

## 1.7.0 (tbd)

- Fixed issue in `piral-vue3` concerning reactivity of props (#720)
- Updated to latest version of `dets`
- Updated website emulator to contain scaffolding tarballs
- Updated pilets to automatically treat defined app shells as shared
- Added support for `shared` key in *piral.json*

## 1.6.2 (September 27, 2024)

- Fixed `registerBreadcrumbs` in `piral-breadcrumbs` failing when no matcher was specified
Expand Down
8 changes: 8 additions & 0 deletions docs/static/schemas/piral-v0.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@
],
"description": "Defines what isolation / component wrapper is used for components of micro frontends. By default, the 'classic' isolation mode is used."
},
"shared": {
"type": "array",
"items": {
"type": "string",
"description": "Path to the file to consider for sharing from the app shell."
},
"description": "Defines what files to share directly as exports from the app shell."
},
"pilets": {
"type": "object",
"description": "Determines the scaffolding and upgrading behavior of pilets using this Piral instance.",
Expand Down
6 changes: 6 additions & 0 deletions docs/tutorials/13-sharing-from-piral.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ The API can be much more dynamic and powerful (e.g., even coupling to the global

This way is our recommendation for dynamic data and functions that require protection. Besides building convenience wrappers around the global state container it can also leverage pilet specific behavior.

## Extending the App Shell Exports

Our recommendation is to only use the Piral instance from your pilets as a type construct / for development purposes. At runtime no significant exports should be used within a pilet. However, if you really want your pilet to strongly depend on the app shell you can also use full exports using the `shared` key in the *piral.json*.

For more information on this look at the [documentation for sharing dependencies](./15-share-dependencies.md).

## Conclusion

Sharing information from the Piral instance can be done in multiple ways. Depending on the needs of the application and its pilets one way or another may be the best. Usually, an app shell uses all these ways to build an outstanding experience for both - users and developers.
Expand Down
20 changes: 17 additions & 3 deletions docs/tutorials/15-share-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Sharing dependencies is one of the selling points of Piral. The key, however, is

Our recommendation is to keep the sharing of dependencies from the app shell as practical as possible.

## Declarative Sharing from the App Shell
## Sharing from the App Shell

### Declarative Sharing from the App Shell

The easiest way to share dependencies from the app shell is to declare them in the `importmap` section of the *package.json*.

Expand Down Expand Up @@ -58,7 +60,7 @@ you get automatically `tslib` as a shared dependency. If you would also add `pir

You can remove inherited importmaps and replace them by explicit `imports` declarations, too.

## Imperative Sharing from the App Shell
### Imperative Sharing from the App Shell

Dependencies can also be "defined" or explicitly mentioned in the program code of the app shell. The mechanism for this works via the `shareDependencies` option of the `createInstance` function.

Expand Down Expand Up @@ -101,7 +103,7 @@ const instance = createInstance({

By default, we do not recommend exporting functionality from the app shell. A Piral instance should **only deliver types** to the pilets. However, sometimes having a dedicated package for extra functionality would either complicate things or is just not feasible.

## Type Declarations
### Type Declarations

While the explicit way is great for gaining flexibility it comes with one caveat: For this kind of sharing types are not automatically inferred and generated. As a result, we need to place additional typings for our offerings.

Expand Down Expand Up @@ -136,6 +138,18 @@ declare module 'my-app-shell' {

The rule of thumb for sharing the type declarations is: Everything exported top-level will be associated with the app shell, and everything exported from an explicitly declared module will be associated with that module.

### Exported Modules

To simplify the process illustrated in the previous two sections you can use a special key called `shared` in your *pilet.json*, e.g.:

```json
{
"shared": ["./src/externals.ts"]
}
```

This will use the exports from the given modules (in the previous example *./src/externals.ts*) to be available in pilets. Moreover, the given modules will be added to the types, i.e., work as if they had been defined as `extraTypes`, too.

## Sharing from Pilets

The mechanism to share dependencies used in pilets is called "import maps". Import maps are also on the way to becoming [an official standard](https://wicg.github.io/import-maps/).
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
},
"resolutions": {
"chalk": "^4.0.0",
"cookie": "0.7.0",
"node-fetch": "2.6.7",
"postcss": "8.4.40"
}
Expand Down
5 changes: 3 additions & 2 deletions src/converters/piral-vue-3/src/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ export function createConverter(config: Vue3ConverterOptions = {}) {
middlewares.forEach((middleware) => middleware(app));
app.component(selector, createExtension(rootName));
app.mount(el);
!app._props && (app._props = {});
locals.instance = app;
},
update(parent, data, ctx, locals: Vue3State) {
const appInstance = locals.instance._instance;

for (const prop in data) {
locals.instance._props[prop] = data[prop];
appInstance.props[prop] = data[prop];
}
},
unmount(parent, locals: Vue3State) {
Expand Down
18 changes: 11 additions & 7 deletions src/converters/piral-vue-3/src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@ import type { BaseComponentProps, ComponentContext } from 'piral-core';
import { createApp, Component, h } from 'vue';

export function mountVue<T extends BaseComponentProps>(
root: Component<T>,
component: Component<T>,
props: T,
ctx: ComponentContext,
captured?: Record<string, any>,
) {
return createApp({
const data = {
...captured,
...props,
};
const root: Component = {
provide: {
piral: props.piral,
...ctx,
},
props: Object.keys(data),
render() {
return h(root as any, {
...captured,
...props,
});
return h(component, this.$props);
},
});
};

return createApp(root, data);
}
1 change: 1 addition & 0 deletions src/framework/piral-core/app.codegen
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module.exports = function () {
publicPath: process.env.PIRAL_PUBLIC_PATH || '/',
debug: debug && (cfg.debugSettings || {}),
emulator: !!process.env.DEBUG_PILET,
shared: Array.isArray(cfg.shared) ? cfg.shared : [],
isolation: cfg.isolation || 'classic',
};

Expand Down
16 changes: 14 additions & 2 deletions src/framework/piral-core/src/tools/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ interface CodegenOptions {
origin: string;
cat: string;
appName: string;
shared: Array<string>;
externals: Array<string>;
publicPath: string;
isolation: 'classic' | 'modern';
Expand All @@ -97,12 +98,23 @@ interface CodegenOptions {
}

export function createDependencies(imports: Array<string>, exports: Array<string>, opts: CodegenOptions) {
const { root, appName, externals, origin } = opts;
const { root, appName, externals, shared, origin } = opts;
const assignments: Array<string> = [];
const asyncAssignments: Array<string> = [];

if (appName) {
assignments.push(`deps['${appName}']={}`);
const parts = [];

for (const item of shared) {
if (typeof item === 'string') {
const path = getModulePathOrDefault(root, origin, item);
const ref = `_${imports.length}`;
parts.push(`...${ref}`);
imports.push(`import * as ${ref} from ${JSON.stringify(path)}`);
}
}

assignments.push(`deps['${appName}']={${parts.join(',')}}`);
}

for (const external of externals) {
Expand Down
2 changes: 1 addition & 1 deletion src/tooling/piral-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
},
"dependencies": {
"css-conflict-inspector": "^0.2.1",
"dets": "^0.16.0",
"dets": "^0.16.4",
"kras": "^0.17.0",
"rimraf": "^3.0.0",
"typescript": "^5.0.0",
Expand Down
13 changes: 12 additions & 1 deletion src/tooling/piral-cli/src/apps/add-piral-instance-pilet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {
findPiletRoot,
piletJson,
ensure,
readPiralPackage,
checkAppShellPackage,
ForceOverwrite,
copyPiralFiles,
} from '../common';

export interface AddPiralInstancePiletOptions {
Expand Down Expand Up @@ -76,7 +80,14 @@ export async function addPiralInstancePilet(baseDir = process.cwd(), options: Ad
if (piletJsonPath) {
const piletJsonDir = dirname(piletJsonPath);
const root = await findPiletRoot(piletJsonDir);
await installPiralInstance(app, fullBase, root, npmClient, selected);
const packageName = await installPiralInstance(app, fullBase, root, npmClient, selected);
const piralInfo = await readPiralPackage(root, packageName);
const isEmulator = checkAppShellPackage(piralInfo);

if (isEmulator) {
// in the emulator case we get the files (and files_once) from the contained tarballs
await copyPiralFiles(root, packageName, piralInfo, ForceOverwrite.yes, {});
}
} else {
log('piletJsonNotAvailable_0180', targetDir);
}
Expand Down
29 changes: 16 additions & 13 deletions src/tooling/piral-cli/src/common/declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,31 @@ function findPiralBaseApi(root: string, framework: string) {
}
}

function findDeclaredTypings(root: string) {
function isString(n: any) {
return typeof n === 'string';
}

function findDeclaredTypings(root: string, shared: Array<string> = []) {
const types = shared.filter(isString).map((file) => resolve(root, file));

try {
const { typings, extraTypes } = require(resolve(root, 'package.json'));

if (extraTypes) {
if (typeof extraTypes === 'string') {
return [resolve(root, extraTypes)];
if (isString(extraTypes)) {
return [resolve(root, extraTypes), ...types];
} else if (Array.isArray(extraTypes)) {
return extraTypes.filter((types) => typeof types === 'string').map((types) => resolve(root, types));
const items = extraTypes.filter(isString).map((file) => resolve(root, file));
return [...items, ...types];
}
}

if (typings) {
return [resolve(root, typings)];
return [resolve(root, typings), ...types];
}
} catch {}

return [];
return types;
}

async function getAllFiles(entryModules: Array<string>) {
Expand Down Expand Up @@ -128,11 +135,7 @@ function createLogger(): Logger {
};
}

async function createDeclarationFile(
options: DeclOptions,
target: string,
forceOverwrite: ForceOverwrite,
) {
async function createDeclarationFile(options: DeclOptions, target: string, forceOverwrite: ForceOverwrite) {
progress('Bundling declaration file ...');
const result = await generateDeclaration(options);

Expand Down Expand Up @@ -190,14 +193,14 @@ export async function createPiralDeclaration(
) {
progress('Reading configuration ...');
const entryFiles = await retrievePiralRoot(baseDir, entry);
const { name, root, externals, framework } = await retrievePiletsInfo(entryFiles);
const { name, root, externals, framework, shared } = await retrievePiletsInfo(entryFiles);
const entryModules = await getEntryModules(entryFiles);
const files = await getAllFiles(entryModules);
const options: DeclOptions = {
name,
root,
files,
types: findDeclaredTypings(root),
types: findDeclaredTypings(root, shared),
apis: findPiralBaseApi(root, framework),
noModuleDeclaration: true,
imports: flattenExternals(externals, true),
Expand Down
Loading
Loading