Support the ongoing development of Laravel.io →
JavaScript Mix
Last updated by @homestar9 6 months ago.
0

The way people do this in javascript land is to use a monorepo that contain both your apps and shared libraries, you can also use git submodules but that is a headache to work with

Last updated 6 months ago.

homestar9 liked this reply

1

Thank you for the reply @wizzymore. I hadn't even heard of a monorepo before your post, and I spent a few hours on YouTube last night digesting the topic. It's an interesting concept that I will have to dig into deeper. It also sounds like there are some serious performance considerations if the project becomes very large.

Based on my (very) limited knowledge of monorepos, it looks like the entire codebase should revolve around a single business organization. However, I'm trying to think in terms of having a core app that might be shared amongst multiple organizations and each organization might want to install various "plug-in" modules that should share the core app's dependencies and may have unique dependencies of their own. Some clients might use plugin "Foo", whereas others might use plugin "Bar", or maybe even a custom plugin of their own.

The best analogy I can think of might be something like Wordpress. The Wordpress blogging app is the core library, and 3rd parties create plugins for the app which extend it's functionality. However, I'm more interested in the client-side Javascript side of things, not the server-side.

Another thought I had would be to look into some type of Javascript dependency injection framework, which could (in theory) dynamically inject dependencies as they are needed.

0

Hi again,

First things first, dependency injection will work like in Javascript, is to insert classes, values, etc.. Not "dependencies" as libraries.

If monorepos is not something that is ok with your project you can stiil use the "thinking" from monorepos to make it work for you. The way monorepos work is that in the monorepo you have PROJECTS and LIBRARIES and they can be shared because you can import them directly as they are in the same project.

What you can do instead is have the Libraries deployed as a package or multiple packages in NPM and then just install your package and you can use it.

As an example, i have a public library that i use in almost all my projects to use "fetch": https://github.com/wizzymore/http Because i had to copy-paste the code base in 10 projects and when i wanted to fix a bug or change something i had to do it in 10 places i just made it a library and deployed it to npm so i can install it in my projects.

The same thing with a package called Turbo, because i use Hotwire in 5 projects and i had to do some custom stuff for it to work, instead of managing it in 5 different places i extracted it to a library and moved it to packagist: https://packagist.org/packages/eptic/turbo

But, do i recommend that you do something like this, as per your example, with datatables and jquery? No, absolutely no. If you have parts of code that are repeating and you can extract them you can create them as libraries, but having dependencies bundled just to have an easier install it's not something i agree with. My opinion aside, you can still do it.

homestar9 liked this reply

1

I have a few follow-up questions, if you don't mind. I want to make sure I understand your approach.

What you can do instead is have the Libraries deployed as a package or multiple packages in NPM and then just install your package and you can use it.

If you do that, wouldn't each of your apps have redundant copies of libraries? This makes perfect sense if you had different apps running separately (say, for different clients on different servers). You can re-use your collection of dependencies because you have them stored in NPM. However, if you installed two apps under the same root application on the same web server, you would have two nearly identical vendor.js library files that the browser would need to download.

If I am understanding correctly, this would solve the problem of making 3rd party libraries available, but it creates a new problem of redundancy because of the two vendor files with much of the same packages in it.

I'll describe in more detail what I'm doing in the hopes that it helps clarify things:

  • I've created a content management system (CMS) using an HMVC approach (hierarchical model view controller).
  • The CMS core is a module that gets installed in the root web app.
  • I want to create plugins for the CMS and know that the plugins will always be installed in the same web app as the core CMS.
  • If possible, I want the plugin module to share JavaScript dependencies/libraries.

The HMVC modular server-side stuff works great... I can leverage the CMS module layouts, views (blades), and more in the plugin modules, but it's the client-side JavaScript that's giving me trouble. The only way I have been able to get a plugin to share dependencies is to either make them globally accessible (i.e. window.DataTable = DataTable;) or do something similar to what you mentioned by having the plugin use nearly identical NPM modules in its own package.json file.

I created a diagram to illustrate what I'm trying to accomplish if it's even possible. Does this help clear things up?

diagram

0

The "attaching objects to window" method that you shared is the correct approach here. There is nothing wrong with it and it will work perfectly for you.

Also, if you are not creating multiple ".js" files (you only have manifest.js and app.js, excluding vendor) and you are not using http2 ( but not even then ) you should not create a vendor.js file. Your code base in the end will be bigger, if you are not using http2 there will be an additional SSL handshake that needs to happen for your end user to download the javascript and you create a dependency between the 2 files, because one simply doesn't work without the other, so it just creates more failing points.

BAD PRACTICE WARNING But, there is a way, maybe not a good one, but there is always a solution for all the possible problems.

You can simply add in mix a new entry that gets the .js file from the vendor ( this will require your CMS module's (not plugin) package.json file to contain any additional dependency that it's missing compared to the intalled CMS plugin).

The line would go:

mix.js('src/app.js', 'dist/app.js'); // FROM THIS
mix.js(['src/app.js', 'vendor/package_org/package_name/resources/js/app.js'], 'dist/app.js'); // TO THIS

This is a trick, you can come with better solutions, maybe having dynamic imports using node's file reading capabilities so on and so forth. Not recommended, but doable.

homestar9 liked this reply

1
Solution selected by @homestar9

I'm sorry for not getting back to you sooner. I spent a lot of time considering your last response, and I believe you are correct. Attaching the objects you want to be available to plugin modules to the window is an acceptable way to solve the problem.

I know making too many things global is a code-smell, but when dealing with plugins, you need to provide access somehow, and in the JavaScript world, the window object feels like the best way to accomplish this task.

I didn't fully understand the "bad practice warning" solution, but since you suggest it's a bad practice, it is probably best to avoid it anyway. :)

Thank you for taking the time to help me out! I appreciate it!

0

Sign in to participate in this thread!

Eventy

Your banner here too?

Dave L homestar9 Joined 22 Sep 2023

Moderators

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2024 Laravel.io - All rights reserved.