Skip to content
This repository has been archived by the owner on Dec 5, 2022. It is now read-only.

Fragment-common, Vue 3 & RequireJS #343

Open
Oskar-Nilsen-Roos opened this issue Oct 18, 2021 · 5 comments
Open

Fragment-common, Vue 3 & RequireJS #343

Oskar-Nilsen-Roos opened this issue Oct 18, 2021 · 5 comments

Comments

@Oskar-Nilsen-Roos
Copy link

Oskar-Nilsen-Roos commented Oct 18, 2021

Hi! I've been trying to create a "fragment-common" for resources that are to be shared between our micro frontends, and I haven't been able to find an example of someone bundling Vue as a shared resource.

The only way I got it working was through a script tag, pointing to a bundle.js with Vue. However, what we actually want is a regular fragment tag so we can point our shared JS resources through a Link header instead, but I haven't been able to get this working.

My current solution looks something like this:

common.js

exports.Vue = require('vue/dist/vue.esm-bundler')

webpack.config.js

var webpack = require('webpack')

module.exports = {
  entry: './common.js',
  output: {
    path: __dirname + '/public',
    filename: 'bundle.js',
    libraryTarget: 'umd',
  },
}

base-template.html

<head>
    <script src="http://localhost:6006/fragment-common/public/bundle.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.min.js" crossorigin=""></script>
</head>
<body>

  <p id="app">{{user}}</p>

  <script>
      const RootComponent = {
        setup() {
          return {user: 'Test'};
        }
      };
      const app = Vue.createApp(RootComponent);
      app.mount('#app');
  </script>
</body>

And this also comes with a caveat, I noticed that if RequireJS (automatically imported by tailor) comes before the bundle.js script, Vue won't load. I don't know why this is. As far as I know there's no nice way to make sure RequireJS loads after, but I solved it by passing an empty string to the amdLoaderURL option in the Tailor config like so:

const tailor = new Tailor({
  fetchTemplate: fetchTemplateFs(
    path.join(__dirname, 'templates'),
    baseTemplateHeaderFn
  ),
  fetchContext: (req) => {
      ...
  },
  filterRequestHeaders: filterHeadersFn,
  amdLoaderUrl: ""
)}

Which results in the following when Tailor tries to set it:

<script src="" crossorigin=""></script>

Where it is later imported manually by setting it in the template instead.

I have tried different ways of solving this, with different webpack builds and also this solution, but to no avail.

TLDR: How do I share Vue in a common fragment, passing it with a Link header to Tailor on fragment request?

@stevoPerisic
Copy link

stevoPerisic commented Oct 18, 2021 via email

@Oskar-Nilsen-Roos
Copy link
Author

Thank you for your input, that does make sense. We have thought some about what it's going to look like when we, for example, eventually transition from all apps running Vue 3, to all except one which is running Vue 4. In this case we'd have to bundle two different versions of Vue into our common fragment until all have transitioned properly. Is this similar to how you've had to solve it too?

I'm not too familiar with tree shaking, is it possible for it to solve my Vue issue, as in at runtime? I read the article but as far as I can understand it only applies to reducing dead code in the same project, not across several different apps running on the same page, potentially with different build configs. Do correct me if I'm wrong!

@stevoPerisic
Copy link

stevoPerisic commented Oct 19, 2021 via email

@Oskar-Nilsen-Roos
Copy link
Author

Okay, then our current solution doesn't seem too bad to share Vue between a few fragments 😄 But I will keep in mind your tip of not getting stuck in the script trap. Tree-shaking still seems like it would be a great addition to reduce our load times though!

If people don't mind I'd like to keep the issue open for anyone that might have solved this with the RequireJS define script, or ran into the weird Vue + RequireJS load order thing.

@aviranbergic
Copy link

@Oskar-Nilsen-Roos not sure it helps you now but what we do is as follows:
we have a common-fragment that brings all shared dependencies to the page

<script>
                     (function (d) {
                       require(d);
                       var arr =  [
                         'react','react-dom',
                         'redux','react-redux','redux-thunk',
                         'redux-dynamic-modules',
                         'redux-dynamic-modules-thunk',
                         'redux-dynamic-modules-react',
                         'redux-dynamic-modules-core',
                         'styled-components',
                         'i18n-react'
                        ];
                       while (i = arr.pop()) (function (dep) {
                           define(dep, d, function (b) {
                               return b()[dep];
                           })
                       })(i);
                      }(['/res/fgmt/common/v/1.1.103/bundle.js']));
                   </script>

on each one of the fragments we define these packages as externals

xternals: {
    react: 'react',
    'react-dom': 'react-dom',
    'react-redux': 'react-redux',
    redux: 'redux',
    'redux-thunk': 'redux-thunk',
    'redux-dynamic-modules': 'redux-dynamic-modules',
    'redux-dynamic-modules-thunk': 'redux-dynamic-modules-thunk',
    'redux-dynamic-modules-react': 'redux-dynamic-modules-react',
    'redux-dynamic-modules-core': 'redux-dynamic-modules-core',
    'styled-components': 'styled-components',
    'i18n-react': 'i18n-react',
  }

we use tree shaking and each fragment is about 90kb.

our common fragments do not only bring libraries but we also initialize redux store and populate cross-application data in the store so all fragments can access if they need. (we still maintain a clear separation of concerns between fragments, common is the exception)

we use redux dynamic modules to be able to append reducers to store post initialization.

hops thats help somehow.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants