Code Monkey home page Code Monkey logo

Comments (86)

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 31

ill raise this with Microsoft - they will have to support federation since they are going to be using it heavily

from module-federation-examples.

maraisr avatar maraisr commented on May 22, 2024 30

What I have done is use node to generate a .d.ts file, that are loaded by our global.d.ts file.

So each Remote outputs a .d.ts file that go declare module "dlaWidgets/Widets" {}, with using the ts.createProgram you can tap into the typeChecker stuff that i use to print its public api. Kinda like getting tsc to ouput definition files, but instead spit them into a single file.

Then each of my hosts import this .d.ts file, which I have registered in a global.d.ts, that all of my projectReferenced monorepo apps include.

So there is a small disconnect between a webpack config, and the types. But any exposed things, are automagically available with types in my entire app. So ts might say its a valid import, but just need to actially configure it with webpack also.

Working on open sourcing this generative thing - just gotta make sure it works in all use cases.

from module-federation-examples.

ruanyl avatar ruanyl commented on May 22, 2024 26

Sharing my setup:

For the host which exposes modules

  1. I created a dts-loader which will emit and collect the .d.ts file. And also it generates the entry .d.ts file based on the exposes.
  2. Then I create a tarball(.tgz file) for the emitted types & entries. And I deployed this tarball with the application's statics, for example, to http://localhost:9000/app-dts.tgz

For the host which requires remotes

  1. I created a webpack plugin WebpackRemoteTypesPlugin which will download and unpack the tarball from remote automatically when running webpack.

More details can be found here: https://github.com/ruanyl/dts-loader
Comments & feedbacks are welcome :)

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 26

I'm not a TS user so I'm no help here.

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 18

We have released a Federated Types Plugin beta.

Theres some gaps in the type def bundling, we are aware of it and working on improvements.

https://app.privjs.com/buy/packageDetail?pkg=@module-federation/typescript

from module-federation-examples.

echarles avatar echarles commented on May 22, 2024 13

@maraisr your approach sounds very interesting. Keep us posted if you open source it.

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 12

Or have a monorepo of types

from module-federation-examples.

OriAmir avatar OriAmir commented on May 22, 2024 9

More then 1 year from the day that issue was open , do we have some good solution how we can resolve that issue and make typescript work well with the plugin ? Tnx

@ScriptedAlchemy

from module-federation-examples.

micmro avatar micmro commented on May 22, 2024 8

Depending on your use case/setup you could solve this by having a tsconfig.json in the project root and leverage path-mapping to resolve the apps entry points (Remote Name + Exposed module):

/tsconfig.json:

...
"paths": {
      "app1/Remote": ["./packages/app1/src/app"],
      "app2/Remote": ["./packages/app2/src/app"]
}
...

/packages/app1/tsconfig.json & /packages/app2/tsconfig.json:

{
  "extends": "../../tsconfig.json"
}

I've setup a little prototype using this setup: https://github.com/rangle/federated-modules-typescript

from module-federation-examples.

mizx avatar mizx commented on May 22, 2024 8

What I have done is use node to generate a .d.ts file, that are loaded by our global.d.ts file.

So each Remote outputs a .d.ts file that go declare module "dlaWidgets/Widets" {}, with using the ts.createProgram you can tap into the typeChecker stuff that i use to print its public api. Kinda like getting tsc to ouput definition files, but instead spit them into a single file.

Then each of my hosts import this .d.ts file, which I have registered in a global.d.ts, that all of my projectReferenced monorepo apps include.

So there is a small disconnect between a webpack config, and the types. But any exposed things, are automagically available with types in my entire app. So ts might say its a valid import, but just need to actially configure it with webpack also.

Working on open sourcing this generative thing - just gotta make sure it works in all use cases.

In addition to this approach, what about packaging that d.ts ouput file and deploying it as a tar.gz alongside your webpack artifacts? Similar to a @types/* package except not published to registry. Then a host app can optionally add dev-dependency referencing the remote tar.gz file and always have latest TS types.

I think this approach would work well for non-monorepo cases.

from module-federation-examples.

glebmachine avatar glebmachine commented on May 22, 2024 7

@zhangwilling it's not a part of IDE, it's all about typechenking of typescript compiler itself

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 6

yeah IDE can solve it, assuming it supports that. Meeting with Microsoft in august - seeking changes to TS to support MF, in doing so IDEs will have to follow the spec

from module-federation-examples.

gthmb avatar gthmb commented on May 22, 2024 6

I would love some feedback on how I am currently solving this issue:

I have a mono-repo with several packages. Each package defines a federation.config.json file that declares its remote name and what it exposes, like so:

packages/app2/config/federation.config.json

{
    "name": "app2",
    "filename": "remoteEntry.js",
    "exposes": {
        "./Button": "./app2/Button"
    }
}

The webpack config file for the module imports this config and spreads it into the plugin config like:

packages/app2/config/webpack.config.js

plugins: [
    new ModuleFederationPlugin({
        ...federationConfig,
        shared: {
            ...deps,
        },
    }),
],

I then have an NPM module I am calling federated_types which exposes a CLI command called make-federated-types which can be called via an npm script in a package.

This command finds and reads the package's federation.config.json and uses the TS compiler to generate types with a similar process to what @maraisr described - however I write the types into an @types/__federated_types directory under the projects node_modules directory. This is nice because there is no extra resolution configuration needed in the tsconfig file or webpack config files since they look in @types as a default location.

The command does allow for specifying where the federated typing files should be written, but by default, it writes to the node_modules/@types/__federated_types directory.

Then in each package.json, I added an entry to the scripts node, like:

  "scripts": {
        "make-types": "make-federated-types"
    },

And since I'm using Lerna, when I run lerna run make-types it generates the typings for the items I have exposed via federation

Does this seem like a sound approach? Is writing to the node_modules directory a bad idea? Is there a better location to write to?

from module-federation-examples.

gthmb avatar gthmb commented on May 22, 2024 6

Very cool. I am happy to help!

If it's useful to anyone looking at sharing type definitions between their packages in a mono-repo, here is what I am using: https://github.com/pixability/federated-types

from module-federation-examples.

grzegorzjudas avatar grzegorzjudas commented on May 22, 2024 6

I was able to get my project with module federation and typescript working, along with typesafety of remote components, with minimal cost:

  • Each remote application has a declaration.d.ts file in the root defining the props of exposed components:
declare module "app2/App" {
    type Props = import('./src/components/App/App').Props;

    const App: React.FunctionComponent<Props>;

    export default App;
}
  • Parent application has the following entry in tsconfig.json:
{
    "include": [
        "../*/*.d.ts"
    ]
}

in this scenario the lazy-loaded components are still reporting missing/incorrect props passed. The only con I can see here is that you need to make sure every newly exposed component is added to the .d.ts file, but that's a minimal cost. Also, make sure you've set "module": "esnext" in compilerOptions in your tsconfig.json - setting "commonjs" will result in console error reg. shared module not being available.

EDIT: One more (cosmetic) issue is, that VSCode's built-in TS server doesn't seem to recognize the "include" part of tsconfig.json resulting in marking the dynamic import in parent app as error (Cannot find module 'app2/App' or its corresponding type declarations) but the build works fine. If anyone knows a fix for this, I'd be ever so grateful.

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 6

Typescript support will be implemented as a built-in capability in the coming iteration of module federation. Colloquially known as "v1.5"

You will see this in https://modernjs.dev as well

from module-federation-examples.

flyyuan avatar flyyuan commented on May 22, 2024 5

Here is a better solution with Typescript.
Form a closed loop of types, from generation to reference complete for Module Federation project.
https://github.com/efoxTeam/emp/tree/main/packages/emp-tune-dts-plugin

from module-federation-examples.

jrandeniya avatar jrandeniya commented on May 22, 2024 5

If anyone is looking for a poly-repo solution, I've put together this sample app with some instructions to share the type definitions of exposed files: https://github.com/jrandeniya/federated-types-sample

It's relatively straight forward using the great work done by @touk/federated-types and webpack-remote-types-plugin

from module-federation-examples.

alexis-regnaud avatar alexis-regnaud commented on May 22, 2024 4

Sharing my setup:

For the host which exposes modules

  1. I created a dts-loader which will emit and collect the .d.ts file. And also it generates the entry .d.ts file based on the exposes.
  2. Then I create a tarball(.tgz file) for the emitted types & entries. And I deployed this tarball with the application's statics, for example, to http://localhost:9000/app-dts.tgz

For the host which requires remotes

  1. I created a webpack plugin WebpackRemoteTypesPlugin which will download and unpack the tarball from remote automatically when running webpack.

More details can be found here: https://github.com/ruanyl/dts-loader
Comments & feedbacks are welcome :)

Does this solution work well with Polyrepo as well?

from module-federation-examples.

popuguytheparrot avatar popuguytheparrot commented on May 22, 2024 4

I'm not a TS user so I'm no help here.

Who can discuss on this theme? Maybe RFC or something else? 2y opened issue with common case where answer is "I'm not a TS" look weird

from module-federation-examples.

steven-prybylynskyi avatar steven-prybylynskyi commented on May 22, 2024 4

For anyone interested, at Cloudbeds, we've released a public NPM package that was built on top of existing solutions

https://www.npmjs.com/package/@cloudbeds/webpack-module-federation-types-plugin

It's also planned to open source it on Github

from module-federation-examples.

lm2almeida avatar lm2almeida commented on May 22, 2024 3

Is anyone having issues with eslint when importing a federated module?

image
image

👇 eslint config

{
  "env": {
    "browser": true,
    "jest": true
  },
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": 12,
    "sourceType": "module"
  },
  "extends": [
    "airbnb",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:jest/recommended",
    "prettier/@typescript-eslint",
    "plugin:prettier/recommended"
  ],
  "plugins": ["react", "react-hooks", "@typescript-eslint", "jest", "prettier"],
  "rules": {
    "import/extensions": "off",
    "import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn",
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off",
    "react/jsx-uses-react": "off",
    "react/jsx-filename-extension": [1, { "extensions": [".ts", ".tsx"] }],
    "react/jsx-one-expression-per-line": "off",
    "import/prefer-default-export": "off",
    "@typescript-eslint/no-unused-vars": "error",
    "@typescript-eslint/explicit-module-boundary-types": "off",
    "prettier/prettier": "error"
  },
  "settings": {
    "import/resolver": {
      "typescript": {}
    }
  }
}

👇 tsconfig

{
  "compilerOptions": {
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "lib": ["dom", "dom.iterable", "esnext"],
    "moduleResolution": "node",
    "noEmit": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true,
    "baseUrl": "./src",
    "paths": {
      "routes/*": ["routes/*"],
      "services/*": ["services/*"],
      "pages/*": ["pages/*"],
      "components/*": ["components/*"]
    }
  },
  "include": ["src"]
}

Thanks! 🙏

from module-federation-examples.

simonepizzamiglio avatar simonepizzamiglio commented on May 22, 2024 3

Depending on your use case/setup you could solve this by having a tsconfig.json in the project root and leverage path-mapping to resolve the apps entry points (Remote Name + Exposed module):

/tsconfig.json:

...
"paths": {
      "app1/Remote": ["./packages/app1/src/app"],
      "app2/Remote": ["./packages/app2/src/app"]
}
...

/packages/app1/tsconfig.json & /packages/app2/tsconfig.json:

{
  "extends": "../../tsconfig.json"
}

I've setup a little prototype using this setup: rangle/federated-modules-typescript

This is the easier and quickest solution that worked for me!
Thanks @micmro 🙏🏻

from module-federation-examples.

malopgrics avatar malopgrics commented on May 22, 2024 3

We have released a Federated Types Plugin beta.

Theres some gaps in the type def bundling, we are aware of it and working on improvements.

https://app.privjs.com/buy/packageDetail?pkg=@module-federation/typescript

It looks promising. Is there a plan to open source it in regular npm ?

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 3

If we can merge or open PRs to module-federation/typescript to improve the "official" plugin that would be great.
We open-sourced it to try and get more input and help since i dont write TS
I just know webpack very well haha

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 2

I found some devs solving this by modifying TS loader. Specifically for module Federation

from module-federation-examples.

ckken avatar ckken commented on May 22, 2024 2

how to fix it

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 2

Will check this out and see what's needed to make this work for both poly and monorepo

from module-federation-examples.

ckken avatar ckken commented on May 22, 2024 2

Has anyone got a reliable solution for projects that don't use a monorepo?

https://github.com/efoxTeam/emp/tree/main/packages/emp-tune-dts-plugin

from module-federation-examples.

adrianbw avatar adrianbw commented on May 22, 2024 2

For those of you creating .d.ts files, do you also have enums? I tried that approach earlier this year and found that my runtimes would throw up because enums need to be compiled to (extraordinarily weird) JS. Maybe I was doing something wrong?

from module-federation-examples.

sabeekaq avatar sabeekaq commented on May 22, 2024 2

Sharing my setup:

For the host which exposes modules

  1. I created a dts-loader which will emit and collect the .d.ts file. And also it generates the entry .d.ts file based on the exposes.
  2. Then I create a tarball(.tgz file) for the emitted types & entries. And I deployed this tarball with the application's statics, for example, to http://localhost:9000/app-dts.tgz

For the host which requires remotes

  1. I created a webpack plugin WebpackRemoteTypesPlugin which will download and unpack the tarball from remote automatically when running webpack.

More details can be found here: https://github.com/ruanyl/dts-loader Comments & feedbacks are welcome :)

I was able to get this working in a polyrepo. One thing that tripped me up pretty hard was your exposes must explicitly reference the files you're exposing.

  exposes: {
    './theme': './src/themes/index.ts',
    './helpers': './src/helpers/index.ts',
    './constants': './src/constants/index.ts',
  }

This will not work:

  exposes: {
    './theme': './src/themes,
    './helpers': './src/helpers',
    './constants': './src/constants,
  }

Opened up this issue so hopefully it can be improved: ruanyl/dts-loader#7

Also, I was able to automate the archiving by using tar-webpack-plugin, so my types are generated and synced whenever I npm start - pretty neat!

Could you please share how you got tar-webpack-plugin to work?

from module-federation-examples.

steven-prybylynskyi avatar steven-prybylynskyi commented on May 22, 2024 2

Now we are trying to achieve that with Federated Types Plugin beta.

It would be really great if the closed source plugin would have an official place to open issues. Probably this thread is currently serves this purpose

from module-federation-examples.

MR-BH avatar MR-BH commented on May 22, 2024 2

We have released a Federated Types Plugin beta.

Theres some gaps in the type def bundling, we are aware of it and working on improvements.

https://app.privjs.com/buy/packageDetail?pkg=@module-federation/typescript

I want to contribute to the repo, is there any way I can join the work? Wait for your reply. @ScriptedAlchemy

from module-federation-examples.

gauravmakkar avatar gauravmakkar commented on May 22, 2024 2

@ScriptedAlchemy Any plan to add typescript support in federated modules?

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024 2

https://www.npmjs.com/package/@module-federation/typescript

from module-federation-examples.

vadym-oliinyk avatar vadym-oliinyk commented on May 22, 2024 2

@ScriptedAlchemy can you link the github repo?

I suppose https://github.com/module-federation/typescript

from module-federation-examples.

zhangwilling avatar zhangwilling commented on May 22, 2024 1

i think it should be solved by IDE, such as vscode.

from module-federation-examples.

maraisr avatar maraisr commented on May 22, 2024 1

I like the IDE idea @zhangwilling, but that will be more about aiding the development flow. However... I think this should still remain in the compiler itself, or a definition file that the compiler reads in. Personally feel its the latter.

If you solve to get the compiler to be aware of the remotes, then you don't have to worry about IDE, and specific IDE support as all IDE's will get this knowledge for free.

My solution outlined above still holds true. Its not terribly bad to implement. I'm hoping to get something open sourced soon.

Just wanting to get an idea from the community:

  1. Are you using a monorepo?
  2. Are your exposes objects exposed as standard javascript/typescript files? (Rather than inline in your webpack.config.js)
  3. Are the request's standard node-esk requests, ie no @svgr/webpack!./icon.svg, where the request would firsts require a loader?

I've taken some assumptions to how I build software, but just wanting to get more scope so that this tool when released would solve issues for the majority.

from module-federation-examples.

steven-prybylynskyi avatar steven-prybylynskyi commented on May 22, 2024 1

Compared to @touk/federated-types, instead of a single file with all types, @module-federation/typescript recreates the directory structure which is neat.

There's one serious issue with @module-federation/typescript plugin is that the types cannot be used for microfrontends that are served from production environment (unless we don't know something). E.g. imagine there are 10 federated apps

  1. shell - served with webpack-dev-server from localhost:4242
  2. commonLibs - from localhost:4243
  3. wmf3 - from https://production.com/wmf3
  4. wmf4 - from https://production.com/wmf4
  5. ...

Some are served with webpack-dev-server, others from production (e.g. CDN, AWS Cloudfront, etc.). For these we would like to publish an npm package with types.

It doesn't look like @module-federation/typescript has any configuration.

@ScriptedAlchemy are there any hidden options that we could provide to generate types that are usable when published as an NPM package and includes types for modules that expose node_modules? If not, would it be possible to extend the plugin to accommodate for those use-cases?

from module-federation-examples.

steven-prybylynskyi avatar steven-prybylynskyi commented on May 22, 2024 1

Also it suffers from the issue with dynamic imports
image

Even though here are examples in advanced-api and the dynamic System Host. So it's not something unusual to do.

We use the module-federation/external-remotes-plugin to achieve this

Also the Practical Module Federation has an example of Dynamically Loading Federated Modules for Webpack 4 and 5.

@ScriptedAlchemy how we can use the plugin in such environment?

Looks like module-federation/external-remotes-plugin and @module-federation/typescript are currently incompatible

from module-federation-examples.

anthonycaron avatar anthonycaron commented on May 22, 2024 1

I don't know if this was already mentioned in this thread but there are some nice solutions exposed in this blog post: https://spin.atomicobject.com/2022/07/19/typescript-federated-modules/

from module-federation-examples.

echarles avatar echarles commented on May 22, 2024

@ScriptedAlchemy

from module-federation-examples.

saulshanabrook avatar saulshanabrook commented on May 22, 2024

I believe, in our case, we should be able to be fine with not having type checking for remote libraries. We can use shared libraries for extension authors import core libraries, so they don't need to be remote and dynamically imported.

from module-federation-examples.

echarles avatar echarles commented on May 22, 2024

I have tried a hacky way to benefit from type-safety importing the definition of the remote project (app2, here widgets) in the host project (app1). As shown on the below image, lazy returns the correct type and non acceptable props are underlined in red. I guess a solution would be to publish the types separately and a 3rd party could depend on those types.

Screenshot 2020-05-05 at 17 51 48

from module-federation-examples.

echarles avatar echarles commented on May 22, 2024

ill raise this with Microsoft - they will have to support federation since they are going to be using it heavily

Awesome!

from module-federation-examples.

zhangwilling avatar zhangwilling commented on May 22, 2024

mono repo is not recomended when our app is very large,independent repo is better.

💡We can watch and output independent repo's d.ts, then start a server which can make d.ts could be downloaded. When other apps need d.ts,just download it to your project from local server.

from module-federation-examples.

ckken avatar ckken commented on May 22, 2024

same issue and suggest like deno remote url type.d.ts

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024

This remains a solution

What I have done is use node to generate a .d.ts file, that are loaded by our global.d.ts file.

So each Remote outputs a .d.ts file that go declare module "dlaWidgets/Widets" {}, with using the ts.createProgram you can tap into the typeChecker stuff that i use to print its public api. Kinda like getting tsc to ouput definition files, but instead spit them into a single file.

Then each of my hosts import this .d.ts file, which I have registered in a global.d.ts, that all of my projectReferenced monorepo apps include.

So there is a small disconnect between a webpack config, and the types. But any exposed things, are automagically available with types in my entire app. So ts might say its a valid import, but just need to actially configure it with webpack also.

Working on open sourcing this generative thing - just gotta make sure it works in all use cases.

from module-federation-examples.

zhangwilling avatar zhangwilling commented on May 22, 2024

@zhangwilling it's not a part of IDE, it's all about typechenking of typescript compiler itself

@glebmachine yes, it is not part of IDE. Maybe TS can provide extra typing file config, but IDE plugin can do this, it could be improved much by IDE. Same as maven in IDEA, maven is not part of IDEA, but it does. Because it's a very important infrastrure.👻

from module-federation-examples.

zhangwilling avatar zhangwilling commented on May 22, 2024

I like the IDE idea @zhangwilling, but that will be more about aiding the development flow. However... I think this should still remain in the compiler itself, or a definition file that the compiler reads in. Personally feel its the latter.

If you solve to get the compiler to be aware of the remotes, then you don't have to worry about IDE, and specific IDE support as all IDE's will get this knowledge for free.

My solution outlined above still holds true. Its not terribly bad to implement. I'm hoping to get something open sourced soon.

Just wanting to get an idea from the community:

  1. Are you using a monorepo?
  2. Are your exposes objects exposed as standard javascript/typescript files? (Rather than inline in your webpack.config.js)
  3. Are the request's standard node-esk requests, ie no @svgr/webpack!./icon.svg, where the request would firsts require a loader?

I've taken some assumptions to how I build software, but just wanting to get more scope so that this tool when released would solve issues for the majority.

@maraisr
monorepo is not recommend when facing large project. so a large project would be seprated to many litttle repos by domain or module. But, we usually would put them together into same parent directory or we use worksapce in VSCode to oragnize them together logically 😈.

from module-federation-examples.

glebmachine avatar glebmachine commented on May 22, 2024

@zhangwilling yeah

But, typescript are trying to resolve imports. And fails when facing federation module import declaration. It looks like we have to be able to declare special federation modules right into tsconfig.json file or similar way.

For now, i'm workaround this with by loads file by document.createElement('script').

from module-federation-examples.

maraisr avatar maraisr commented on May 22, 2024

You got to be careful with that approach though. It does mean that you cannot also use path mappings for other things in your app, because if you are you're probably also using tsconfig paths webpack resolver, in which case module federation plugin can't "remote" those. You can but you'd have to have a special build-time tsconfig that excludes the MF mappings.

from module-federation-examples.

micmro avatar micmro commented on May 22, 2024

Thanks @maraisr , that is a very good point I had not considered.
I suppose then it is a trade-off of manual remote interface vs potential manual MF path-mapping overwrites.

from module-federation-examples.

doerme avatar doerme commented on May 22, 2024

1.webpack provide a template for the "d.ts" module building
2.webpack config decare the use of remote "d.ts" module
3.IDE support using static inspection for the second point

from module-federation-examples.

ckken avatar ckken commented on May 22, 2024

fix it with npm-dts create in dist & request by app

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024

As long as node resolves properly to the location you write to, it's a sound approach. I think haha.

What one could do is create a GitHub crawler that pulls other repos TS def files remotely (similar to webpack code streaming) and write them on demand. You'd only need a list of repos / remotes to "look" for JS defs to pull ahead of time.

Basically your mono repo idea. Applied to polyrepo and using the network

If anyone wants to try building this- I'll give you maintainer access to a repo under the official MF organization

from module-federation-examples.

gthmb avatar gthmb commented on May 22, 2024

Thanks for the feedback!

For your suggestions around a poly-repo solution, are you thinking an application would have a config file that defined the repos/remotes they are using, and then a script would pull those repos and generate local copies of the types needed?

Just trying to get a clearer picture. I would be happy to work on something like that. Happy and eager to help how I can!

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024

Yeah basically. Imagine you listed an array of objects that contain info about your remotes.

Then we could search git repo via api or just the TS defs related to remote files and write those strings to disk in your types directory

Basically replaced fs with fetch and we get the raw git text from api

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024

This is easier to instrument with federation dashboard because it know what hosts uses what remotes and where they are. In the future I could tack something into dashboard so one could query dashboard for the defs - then write the strings.

from module-federation-examples.

gthmb avatar gthmb commented on May 22, 2024

Cool, I'll check that out too. Thanks!

from module-federation-examples.

rickihastings avatar rickihastings commented on May 22, 2024

Has anyone got a reliable solution for projects that don't use a monorepo?

from module-federation-examples.

rickihastings avatar rickihastings commented on May 22, 2024

@lm2almeida I think the issue is that your TypeScript project doesn't understand what remote is, and therefore eslint doesn't understand it as your eslint is configured to use TypeScript as the import resolver.

As for a solution to the TypeScript issue. The only solutions I've found so far are in this thread and they involve building the types separately and then importing them from somewhere, the main issues I'm seeing with this are the manual steps of building the types, and then syncing up these types across your projects when the files change.

At the moment it's an unsolved problem imo. It's less of an issue in a monorepo though.

from module-federation-examples.

lm2almeida avatar lm2almeida commented on May 22, 2024

@lm2almeida I think the issue is that your TypeScript project doesn't understand what remote is, and therefore eslint doesn't understand it as your eslint is configured to use TypeScript as the import resolver.

As for a solution to the TypeScript issue. The only solutions I've found so far are in this thread and they involve building the types separately and then importing them from somewhere, the main issues I'm seeing with this are the manual steps of building the types, and then syncing up these types across your projects when the files change.

At the moment it's an unsolved problem imo. It's less of an issue in a monorepo though.

Thanks for the answer, @rickihastings. The problem here is that even with the declared typing the error still occurs. Looking forward for a solution 🙏

image

from module-federation-examples.

Kjaer avatar Kjaer commented on May 22, 2024

Whoever stuck on typings here is my approach.

First of all, I am relying on @gthmb 's federated-types package: #20 (comment)

on my remote app, I created federation-config.json

/* federation.config.json */

{
  "name": "blank",
  "exposes": {
    "./RemoteApp": "./src/bootstrap"
  }
}

then, I exporting my typings in a custom @types directory on my root. (remote app)

scripts: {
    "make-types": "make-federated-types --outputDir ./@types/remote-app"
}

federated-types export types inside node_modules as default behaviour. For that reason it does not create package.json if custom output directory set. However, I need the package.json because I am adding my remote app's type as a dependency to my host application.

after running make-types command, it generates the types by looking at my federation-config.json and I manually created package.json. In the end, you should have something similar:

├── @types
│   ├── remote-app
│   │   ├── index.d.ts
│   │   ├── remote-app.d.ts
│   │   ├── package.json

I have my typings ready to be import as a dependency for my host app. On my host app's package.json I added these typings as devDependency

devDependencies: {
 "@types/remote-app": "file:../federated-apps/remote-app/@types/remote-app",
}

then run the yarn install as usual, and all my remote-app's typings are available for the host app, without a hassle. What's good at this, all these typings creations and importing to host app is automated and less error-prone.

from module-federation-examples.

malcolm-kee avatar malcolm-kee commented on May 22, 2024

Sharing a recent setup in my current company that is NOT monorepo (can't share code as it's not open-sourced, but happy to clarify!).

The key components are:

  1. npm org (to publish the exposes type, not the code)
  2. (Optional) A custom pipeline (like CRA) that abstract the webpack config so I can enforce similar conventions for all projects.

The convention that I enforce is that modules that are exposed must be in a src/exposes folder. Then, I programmatically set the exposes key of module federation plugin based on the file, e.g.

return new ModuleFederationPlugin({
  exposes: {
    './exposes/file1': './src/exposes/file1'
  }
})

I have a custom tsconfig.json file that only includes src/exposes folder. When it compiles, it will generate another folder like

type
/exposes
  /file1.d.ts
  /file2.d.ts
/components
  /...

Writing some custom code, I generate a package.json file in that folder with name @npmorg/<appName>, which can be published.

In the host application, when it import the remotes, always use the convention @npmorg/<appName>/exposes/<module> and also install @npmorg/<appName> package (which only consists of type definition).

Everytime the remote app change its interface in exposes file, it just need to regenerate the type definition folder and publish it and the host just need to update that package to get the latest type definition.

from module-federation-examples.

arshita04 avatar arshita04 commented on May 22, 2024

I have a file in my remote which is exporting enums and interfaces and i need to consume this in my host application. My build keeps failing as either it fails with the error: / not declared and when i declare it, it fails with the error: not being used and at the place where i am using it it throws the error: cannot use namespace.

from module-federation-examples.

dgpt avatar dgpt commented on May 22, 2024

Sharing my setup:

For the host which exposes modules

  1. I created a dts-loader which will emit and collect the .d.ts file. And also it generates the entry .d.ts file based on the exposes.
  2. Then I create a tarball(.tgz file) for the emitted types & entries. And I deployed this tarball with the application's statics, for example, to http://localhost:9000/app-dts.tgz

For the host which requires remotes

  1. I created a webpack plugin WebpackRemoteTypesPlugin which will download and unpack the tarball from remote automatically when running webpack.

More details can be found here: https://github.com/ruanyl/dts-loader Comments & feedbacks are welcome :)

I was able to get this working in a polyrepo. One thing that tripped me up pretty hard was your exposes must explicitly reference the files you're exposing.

  exposes: {
    './theme': './src/themes/index.ts',
    './helpers': './src/helpers/index.ts',
    './constants': './src/constants/index.ts',
  }

This will not work:

  exposes: {
    './theme': './src/themes,
    './helpers': './src/helpers',
    './constants': './src/constants,
  }

Opened up this issue so hopefully it can be improved: ruanyl/dts-loader#7

Also, I was able to automate the archiving by using tar-webpack-plugin, so my types are generated and synced whenever I npm start - pretty neat!

from module-federation-examples.

osya avatar osya commented on May 22, 2024

federation.config.json

"filename" is not used by federated-types. So "filename" should stay in webpack.config

from module-federation-examples.

Kjaer avatar Kjaer commented on May 22, 2024

I disagree. In the end, Typescript support must not an official thing for this tech. On the other hand, there are plenty of solutions mentioned above works just fine.

from module-federation-examples.

adrianbw avatar adrianbw commented on May 22, 2024

I do think a good Typescript solution is very important for the long-term success of module federation, given how TS keeps growing in popularity.

Would something like this work?

Package A: The code you want to get through module federation.
Package B: A package that imports Package A through module federation and then re-exports those functions with correct typing.
Package C: Your application, which adds Package B through npm.

Package A and Package B should be published from the same repo, so that you don't have to keep anything in sync between repos. I'm honestly not sure if this method would preserve the benefits of module federation—what happens when webpack runs on package C?

from module-federation-examples.

ckken avatar ckken commented on May 22, 2024

emp v2 work very very use remote d.ts

from module-federation-examples.

makotot avatar makotot commented on May 22, 2024

Although I wonder what should be done when running tsc in CI, I think you can do the same thing with filemanager-webpack-plugin like this without using tar-webpack-plugin.

    new FileManagerPlugin({
      events: {
        onEnd: {
          archive: [
            {
              source: '.wp_federation',
              destination: 'path/to/types.tar.gz',
              format: 'tar',
            }
          ],
        },
      },
    }),

from module-federation-examples.

stefan-toubia avatar stefan-toubia commented on May 22, 2024

I've also been using the tsconfig.json paths solution and it has been working well, but it's not without issues. That is, those remotes that you've configured with paths will still need to be fully installed when you check types, or you'll end up with errors:

./packages/app1/src/app/useSelectedEntity.ts:2:21 - error TS2307: Cannot find module 'lodash/isEqual' or its corresponding type declarations.

2 import isEqual from "lodash/isEqual";
                      ~~~~~~~~~~~~~~~~

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024

We have released a Federated Types Plugin beta.

Theres some gaps in the type def bundling, we are aware of it and working on improvements.

https://app.privjs.com/buy/packageDetail?pkg=@module-federation/typescript

It looks promising. Is there a plan to open source it in regular npm ?

Not currently, I generally only publish OSS to npm. Closed source, even if it's free, usually stays on priv

Perhaps in the future depending on data & feedback during beta & RC phases

from module-federation-examples.

steven-prybylynskyi avatar steven-prybylynskyi commented on May 22, 2024

Hey @ScriptedAlchemy, I'm glad there's finally a solution emerging to share Typescript definitions among microfrontends from the author, despite of saying that I'm not a TS user so I'm no help here.!

I was trying other solutions like @touk/federated-types that reads a federation.config.json and generates types in node_modules@types__federated_types

It does that for local modules but does not collect types for modules that are exposed from node_modules.

Our federation.config.json config looks like this:

{
  "name": "commonLibs",
  "exposes": {
    "./AxiosHttp": "./src/api-services/axios-client/index",
    ...
    "./@cloudbeds/ui-library": "@cloudbeds/ui-library",
    "./react": "react",
    "./react-dom": "react-dom",
    "./react-query": "react-query",
    "./react-router-dom": "react-router-dom"
  }
}

Everything after ... is from node_modules and we want that to be part of commonLibs microfrontend so that will consume a single version of these without even installing react in consuming app's package.json, e.g.

import react from 'commonLibs/react';

Coupled with webpack-remote-types-plugin we could have updated types without uploading them to S3 or publishing to NPM. Unfortunately that doesn’t work with Dynamic remotes - it needs an actual URL from which the remote is served from. We use external-remotes-plugin and uses a dynamic variable name, e.g. [window.commonLibs] instead of localhost:4242

Here's a screen of the error we are experiencing:

image

from module-federation-examples.

steven-prybylynskyi avatar steven-prybylynskyi commented on May 22, 2024

@module-federation/typescript creates types in dist/@mf-typescript

The __types_index.json file contains list of type definition files for all exposed modules, here it's:

[
  "index.d.ts",
  "index.d.ts",
  "index.d.ts",
  "index.d.ts",
  "ui-library.d.ts",
  "react.d.ts",
  "react-dom.d.ts",
  "react-query.d.ts",
  "react-router-dom.d.ts"
]

Although it lists packages in node_modules, e.g. react.d.ts and ui-library.d.ts they are not included in dist/@mf-typescript

Also it would be great if that file's purpose would be documented here

from module-federation-examples.

steven-prybylynskyi avatar steven-prybylynskyi commented on May 22, 2024

I've changed the URL to be localhost in remotes section and now we're getting this 404 error for exposed npm package

\node_modules\got\index.js:482
     proxy.emit('error', new got.HTTPError(statusCode, res.statusMessage, res.headers, opts), null, res);
    ^
GotError [HTTPError]: Response code 404 (Not Found)

  path: '/@mf-typescript/ui-library.d.ts',
  protocol: 'http:',
  url: 'http://localhost:9082/@mf-typescript/ui-library.d.ts',
  statusCode: 404,
  statusMessage: 'Not Found',

image

from module-federation-examples.

steven-prybylynskyi avatar steven-prybylynskyi commented on May 22, 2024

Sorry for the numerous comments, I wish it can be hosted on Github, with Issues/Discussion tabs
It can be an empty repo with a README only.

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024

Already done. App.privjs.com search for module-federation/typescript

We did this months ago

from module-federation-examples.

vmagalhaes avatar vmagalhaes commented on May 22, 2024

I'm searching for a solution with Angular using the new typescript package. I tried to use it but with no success.
But great initiative @ScriptedAlchemy

from module-federation-examples.

steven-prybylynskyi avatar steven-prybylynskyi commented on May 22, 2024

The @cloudbeds/webpack-module-federation-types-plugin is now available on Github. Feel free to use Issues or Discussions tabs.

And let me thank @ScriptedAlchemy for the awesome Module Federation plugin upon which a lot of projects nowadays started to rely on. I hope that some day there won't be a need for a 3rd party plugin to deal with types and there'll be a standard documented way built into Webpack.next

from module-federation-examples.

stefan-toubia avatar stefan-toubia commented on May 22, 2024

@ScriptedAlchemy can you link the github repo?

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024

thats the one, PR's welcome

from module-federation-examples.

sudheerkumar-golla avatar sudheerkumar-golla commented on May 22, 2024

Hey @ScriptedAlchemy, I'm glad there's finally a solution emerging to share Typescript definitions among microfrontends from the author, despite of saying that I'm not a TS user so I'm no help here.!

I was trying other solutions like @touk/federated-types that reads a federation.config.json and generates types in node_modules@types__federated_types

It does that for local modules but does not collect types for modules that are exposed from node_modules.

Our federation.config.json config looks like this:

{
  "name": "commonLibs",
  "exposes": {
    "./AxiosHttp": "./src/api-services/axios-client/index",
    ...
    "./@cloudbeds/ui-library": "@cloudbeds/ui-library",
    "./react": "react",
    "./react-dom": "react-dom",
    "./react-query": "react-query",
    "./react-router-dom": "react-router-dom"
  }
}

Everything after ... is from node_modules and we want that to be part of commonLibs microfrontend so that will consume a single version of these without even installing react in consuming app's package.json, e.g.

import react from 'commonLibs/react';

Coupled with webpack-remote-types-plugin we could have updated types without uploading them to S3 or publishing to NPM. Unfortunately that doesn’t work with Dynamic remotes - it needs an actual URL from which the remote is served from. We use external-remotes-plugin and uses a dynamic variable name, e.g. [window.commonLibs] instead of localhost:4242

Here's a screen of the error we are experiencing:

image

Hi @steven-prybylynskyi , Could you please suggest me the package you have used to build types for modules exposed from node_modules(eg: react).

from module-federation-examples.

ilteoood avatar ilteoood commented on May 22, 2024

Hey @ScriptedAlchemy, I'm glad there's finally a solution emerging to share Typescript definitions among microfrontends from the author, despite of saying that I'm not a TS user so I'm no help here.!
I was trying other solutions like @touk/federated-types that reads a federation.config.json and generates types in node_modules@types__federated_types
It does that for local modules but does not collect types for modules that are exposed from node_modules.
Our federation.config.json config looks like this:

{
  "name": "commonLibs",
  "exposes": {
    "./AxiosHttp": "./src/api-services/axios-client/index",
    ...
    "./@cloudbeds/ui-library": "@cloudbeds/ui-library",
    "./react": "react",
    "./react-dom": "react-dom",
    "./react-query": "react-query",
    "./react-router-dom": "react-router-dom"
  }
}

Everything after ... is from node_modules and we want that to be part of commonLibs microfrontend so that will consume a single version of these without even installing react in consuming app's package.json, e.g.

import react from 'commonLibs/react';

Coupled with webpack-remote-types-plugin we could have updated types without uploading them to S3 or publishing to NPM. Unfortunately that doesn’t work with Dynamic remotes - it needs an actual URL from which the remote is served from. We use external-remotes-plugin and uses a dynamic variable name, e.g. [window.commonLibs] instead of localhost:4242
Here's a screen of the error we are experiencing:
image

Hi @steven-prybylynskyi , Could you please suggest me the package you have used to build types for modules exposed from node_modules(eg: react).

https://github.com/module-federation/universe/tree/main/packages/native-federation-typescript

from module-federation-examples.

ScriptedAlchemy avatar ScriptedAlchemy commented on May 22, 2024

Type Hint Support Tracking: module-federation/core#1943

from module-federation-examples.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.