Giter Site home page Giter Site logo

typescript's Introduction

Typescript support for module federated apps

Project Status

This project is now moved to module-federation/nextjs-mf. All the feature development for this package will be made from the new repo.

Going forward please raise any issues in the NextJs-mf repo.

Installation

$ npm i @module-federation/typescript

Usage

Register the plugin in webpack.config.js file

const FederatedTypesPlugin = require('@module-federation/typescript')

const federationConfig = {
  name: 'my-app',
  filename: 'remoteEntry.js',
  exposes: {
    //...exposed components
    './Button': './src/Button',
    './Input': './src/Input',
  },
  remotes: {
    app2: 'app2@http://localhost:3002/remoteEntry.js',
  },
  shared: ['react', 'react-dom'],
}

plugins: [
  // ...
  new ModuleFederationPlugin(federationConfig),
  new FederatedTypesPlugin(), // Optional: you can pass federationConfig object here as well
]

You need to register this plugin in both remote and host apps. The plugin will automatically create a directory named @mf-typescript in the host app - that contains all the types exported by the remote apps.

In your file:

import RemoteButtonType from "../@mf-typescript/Button";

const RemoteButton = React.lazy(
  () => import("app2/Button")
) as unknown as typeof RemoteButtonType;

Usage in Next.js

You need to manually pass the federationConfig object to the plugin. The remotes value should contain absolute path.

Sample code:

// next.config.js
const FederatedTypesPlugin = require('@module-federation/typescript')

module.exports = {
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
    config.plugins.push(
      new ModuleFederationPlugin(federationConfig),
      new FederatedTypesPlugin({
        ...federationConfig,
        remotes: { app2: 'app2@http://localhost:3000/remoteEntry.js' }
      })
    )
    return config
  },
}

Support

Drop me a message on twitter for support/feedback, or maybe just say Hi at @prasannamestha

Credits

Shoutout to @ScriptedAlchemy for helping with the development of this plugin.

typescript's People

Contributors

kinbaum avatar pavandv avatar prasannamestha avatar renovate[bot] avatar scriptedalchemy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

typescript's Issues

Error Running Webpack-cli

I got this error message after updating to 0.1.9

image

I think there is a typo in your update version 0.1.9 for naming options to compilerOptions but in distPath you still using variable options. I see on PR #6

image

Declaration files emitted doesn't include all the imports

The declaration files emitted from the ts.createProgram doesn't include all the imported modules from the source file.

For ex:

// useConfig.ts

import {InitialConfig} from './initialConfig';

export const useConfig = () => {
  const [config, setConfig] = useState<InitialConfig>();

  const updateConfig = (data: InitialConfig) => {
    setConfig(data);
  }

  return {
    config,
    updateConfig,
  }
};

The declaration file generated from compilation file is as follows:

// useConfig.d.ts

export declare const useConfig: () => {
  config: unknown;
  updateConfig: (data: InitialConfig) => void;
}

ts.createProgram is not including InitialConfig as part of the generated .d.ts file, and as such we can't be able to use any types generated.

Error fetching types - not exposed by remote app (nextjs-mf)

Apologies if I'm being dumb, I'm getting an error similar to #21
in my container app it's failing to fetch types from the remote app

ERROR fetching/writing types [AxiosError: Request failed with status code 404] {
  code: 'ERR_BAD_REQUEST',
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [Function: httpAdapter],
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    env: { FormData: [Function] },
    validateStatus: [Function: validateStatus],
    headers: {
      Accept: 'application/json, text/plain, */*',
      'User-Agent': 'axios/0.27.2'
    },
    method: 'get',
    url: 'http://localhost:3001/@mf-typescript/__types_index.json',
    data: undefined
  },

And in the remote app, the types can be found directly under .next which seems to make sense based on the code in this package
image

I'm using v0.2.2 with Next.js
image

Container webpack.config.js

const nextConfig = {
  webpack(config, options) {
    const { isServer } = options;
    if (!options.isServer) {
      const nextFederationConfig = {
        name: "container",
        filename: "static/chunks/remoteEntry.js",
        remotes: {
          home: `home@http://localhost:3001/_next/static/${
            isServer ? "ssr" : "chunks"
          }/remoteEntry.js`,
        },
        exposes: {},
        shared: {},
        ...
      };
      config.plugins.push(
        new NextFederationPlugin(nextFederationConfig),
        new FederationTypesPlugin(nextFederationConfig)
      );
    }
    return config;
  },
};

Remote webpack.config.js

const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  output: "standalone",
  webpack(config, options) {
    const { isServer, webpack } = options;
    if (!options.isServer) {
      const nextFederationConfig = {
        name: "home",
        filename: "static/chunks/remoteEntry.js",
        remotes: {},
        exposes: {
          "./Header": "lib/Header",
          "./Counter": "lib/Counter",
          "./CounterStateLib": "lib/CounterStateLib",
          "./state/counter": "lib/state/counter",
        },
        shared: {},
        ...
      };
      config.plugins.push(
        new NextFederationPlugin(nextFederationConfig),
        new FederationTypesPlugin(nextFederationConfig)
      );
    }

    config.plugins.push(new webpack.EnvironmentPlugin(["APP_ENV"]));
    return config;
  },
};

Let me know if anymore information would help, Thanks

remoteComponents is not defined

1add36f (line 75) introduced an issue removing this key word to access remoteComponents. See:
image

Suggestion:

importRemoteTypes() {
    const remoteUrls = Object.entries(this.remoteComponents).map(([ remote, entry ]) => {
    const [, url ] = entry.split('@');

    return {
      origin: new URL(url ?? entry).origin,
      remote
    };
  })
...

I'd create a PR addressing it but unfortunately I can't :(
image

Local dev testing failing due to https

Hi,
Thanks for writing this module.
I have my federated server running on localhost with https enabled (on port 8080)
It is using the webpack local dev server https, so it has an insecure certificate.

When doing local dev with the regular application, the Axios request is failing due to a self signed certificate:

ERROR fetching/writing types AxiosError: self signed certificate
    at TLSSocket.onConnectSecure (_tls_wrap.js:1515:34)
    at TLSSocket.emit (events.js:400:28)
    at TLSSocket._finishInit (_tls_wrap.js:937:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:709:12) {
  code: 'DEPTH_ZERO_SELF_SIGNED_CERT',
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [Function: httpAdapter],
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    env: { FormData: [Function] },
    validateStatus: [Function: validateStatus],
    headers: {
      Accept: 'application/json, text/plain, */*',
      'User-Agent': 'axios/0.27.2'
    },
    method: 'get',
    url: 'https://localhost:8080/@mf-typescript/__types_index.json',
    data: undefined
  },
  request: <ref *1> Writable {
    _writableState: WritableState {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: false,
      needDrain: false,
      ending: false,
      ended: false,
      finished: false,
      destroyed: false,
      decodeStrings: true,
      defaultEncoding: 'utf8',
      length: 0,
      writing: false,
      corked: 0,
      sync: true,
      bufferProcessing: false,
      onwrite: [Function: bound onwrite],
      writecb: null,
      writelen: 0,
      afterWriteTickInfo: null,
      buffered: [],
      bufferedIndex: 0,
      allBuffers: true,
      allNoop: true,
      pendingcb: 0,
      prefinished: false,
      errorEmitted: false,
      emitClose: true,
      autoDestroy: true,
      errored: null,
      closed: false
    },
    _events: [Object: null prototype] {
      response: [Function: handleResponse],
      error: [Function: handleRequestError],
      socket: [Function: handleRequestSocket]
    },
    _eventsCount: 3,
    _maxListeners: undefined,
    _options: {
      maxRedirects: 21,
      maxBodyLength: 10485760,
      protocol: 'https:',
      path: '/@mf-typescript/__types_index.json',
      method: 'GET',
      headers: [Object],
      agent: undefined,
      agents: [Object],
      auth: undefined,
      hostname: 'localhost',
      port: '8080',
      nativeProtocols: [Object],
      pathname: '/@mf-typescript/__types_index.json'
    },
    _ended: true,
    _ending: true,
    _redirectCount: 0,
    _redirects: [],
    _requestBodyLength: 0,
    _requestBodyBuffers: [],
    _onNativeResponse: [Function (anonymous)],
    _currentRequest: ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: false,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      socket: [TLSSocket],
      _header: 'GET /@mf-typescript/__types_index.json HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'User-Agent: axios/0.27.2\r\n' +
        'Host: localhost:8080\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: noopPendingOutput],
      agent: [Agent],
      socketPath: undefined,
      method: 'GET',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      path: '/@mf-typescript/__types_index.json',
      _ended: false,
      res: null,
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'localhost',
      protocol: 'https:',
      _redirectable: [Circular *1],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype]
    },
    _currentUrl: 'https://localhost:8080/@mf-typescript/__types_index.json',
    [Symbol(kCapture)]: false
  }
}

Any way we can get around this with a config value I pass to the dev webpack config?

Can not determine file extension

This error occurs in a module-federation-examples project. specifically this project https://github.com/module-federation/module-federation-examples/tree/master/typescript/app2 at commit 931ea0e5776d1b1f2c68217d9681e5912cda19ec

error message running yarn start

<e> [webpack-dev-middleware] Error: Can not determine file extension, please include file extension for the file ./src/Button
<e>     at /module-federation-examples/typescript/app2/node_modules/@module-federation/typescript/src/index.js:118:15
<e>     at Array.forEach (<anonymous>)
<e>     at FederatedTypesPlugin.extractTypes (/module-federation-examples/typescript/app2/node_modules/@module-federation/typescript/src/index.js:109:15)
<e>     at FederatedTypesPlugin.run (/module-federation-examples/typescript/app2/node_modules/@module-federation/typescript/src/index.js:64:12)
<e>     at /module-federation-examples/typescript/app2/node_modules/@module-federation/typescript/src/index.js:58:12
<e>     at Hook.eval [as callAsync] (eval at create (/module-federation-examples/typescript/app2/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:9:1)
<e>     at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/module-federation-examples/typescript/app2/node_modules/tapable/lib/Hook.js:18:14)
<e>     at /module-federation-examples/typescript/app2/node_modules/webpack/lib/Compiler.js:1192:33
<e>     at finalCallback (/module-federation-examples/typescript/app2/node_modules/webpack/lib/Compilation.js:2787:11)
<e>     at /module-federation-examples/typescript/app2/node_modules/webpack/lib/Compilation.js:3092:11
^C<i> [webpack-dev-server] Gracefully shutting down. To force exit, press ^C again. Please wait...

This error can be avoided by making this change.

Screenshot 2022-09-16 at 12 41 54

But then a new error occurs

Error saving the types index [Error: ENOENT: no such file or directory, open 'dist/@mf-typescript/__types_index.json'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'dist/@mf-typescript/__types_index.json'
}

Failed to fetch types when types are published to a nested folder

In my project, I am publishing my remoteEntry.js and types to a subfolder:
e.g.
https://mysite/common/remoteEntry.js
and https://mysite/common/@mf-typescript/

But the code here https://github.com/module-federation/typescript/blob/main/src/index.js#L53
assumes we only want the origin of the remote.
But we kind of need the origin and any base path. Is it possible to introduce a config for this plugin to add a basepath to all type fetching?

Initial build checks for types before creating them

Getting the following error on yarn start:

Error saving the types index [Error: ENOENT: no such file or directory, open 'dist/@mf-typescript/__types_index.json'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'dist/@mf-typescript/__types_index.json'
}

To reproduce:

  1. rm -rf dist
  2. yarn start
  3. The directory and file are created on that same build, but only after the check, so it fails

If I kill the process and restart it goes away. Of course, I could just check in this file, but I'd rather not have to check in the dist dir.

If it's relevant, I'm using dynamic imports.

How does @module-federation/typescript serves/exposes emitted files?

My "Shell" app (that doesn't exposes nothing but consumes remote modules) isn't being able to fetch /@mf-typescript/__types_index.json neither *.d.ts files from remotes, it's getting 404 as if ModuleFederation isn't serving/exposing them.

image

I might be missing some config, how does @module-federation/typescript serves/exposes emitted files? ๐Ÿค”

My project is open source, you can try yourself running https://github.com/PokeFederations/web-app on branch @module-federation/typescript (this same branch name exists on each auxiliar modules described in the README file)

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

npm
package.json
  • axios ^0.27.2
  • download ^8.0.0
  • lodash.get ^4.4.2
  • typescript ^4.6.4

  • Check this box to trigger a request for Renovate to run again on this repository

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.