I maintain a (PHP) web application that consists of an application core and several plugins that can be added to the core. Each instance of the application can have a custom set of plugins, depending on the purpose of the instance. The application core and the plugins are developed in their own respective repositories.
If a plugin is installed, it injects its JavaScript into the templates of the frontend. This may look as follows:
<script src="core.min.js"></script>
<script src="plugin-1.min.js"></script>
<script src="plugin-2.min.js"></script>
The ordering is important because a plugin might use resources from the core or another plugin that was injected previously. Currently, this sharing of resources is implemented as a single variable in global scope which collects the resources that are "exported" by the core and plugins. In a plugin, a resource can be accessed and used via this global variable:
var resource = myapp.core.resource;
Now to my question: Is there a way to implement the core/plugin architecture described above with ES6 modules (using Webpack or something similar)? I would like to use a more modern way of developing JavaScript or even use TypeScript but I don't know if or how this can be done. I understand that it might be possible to import some resources from the core JavaScript in a plugin but wouldn't this be compiled into the JavaScript file of the plugin, too? This would duplicate the code.
Clarification:
The core application and plugins are developed in separate repositories, e.g. like this:
core/src/main.js
plugin-1/src/main.js
plugin-2/src/main.js
The code for each repository is built on its own into a PHP package. A final application instance consists of the application core and several plugins which are installed as PHP packages. The JavaScript is not rebuilt when a PHP package is installed.
I could import some resources from the application core in a plugin like this:
import {resource} from '../../../core/src/main'
However, this would duplicate the code of the application core because the core and the plugin are built separately.
What I'm asking is if it's possible to create a build configuration that is "aware" of shared variables between the core and the plugins. For example, if I define a class Main
in the core, it could be built into the global variable myapp.core.Main
. If I then import Main
in one of the plugins, it could be resolved to use the variable myapp.core.Main
, instead. That's how the current implementation works but it's all defined manually. Maybe there is a smarter way with modern build tools like Webpack.
The general point of packing your modules into a bundle.js
is the fact that while they are refracted in the src
, they are still bundled into 1 bundle file (sometimes you split that into a few for various reasons). Webpack knows not to duplicate code, that's the basis of it. I'll give an example:
src:
root/src
root/src/main.js
root/src/plugin1.js
root/src/plugin2.js
root/src/utils/util1.js
so lets say we that main is the the entry point to your app. It uses plugin1
and plugin2
, and both of those make use of util1
.
main.js:
import plugin1 from './plugin1'
import plugin2 from './plugin2'
//... Do stuff
plugin1.js:
import util1 from './utils/util1.js';
export default const plugin1 = ()=>{
//.. Do stuff also with util1
}
plugin2.js:
import util1 from './utils/util1.js';
export default const plugin2 = ()=>{
//.. Do stuff also with util1
}
util1.js:
export default const util1 = ()=>{
//.. Do util things
}
When you use webpack to bundle up this code, it will know not to repeat code. It will know also to do a lot of production quality stuff if you config them properly (and honestly also by default it's pretty good from the get go). The result would go into the bundle and either a generated index.html file (I recommend this method as you can start hashing the names of the sources and avoid caching issue upon updates.) of a manual one.
dist:
root/dist/index.html
root/dist/bundle.js
index.html:
<!-- Would / Should have a script tag for the bundle. -->
<script src="bundle.js">
bundle.js:
// Here you would get a minified/uglified etc. version of your JS which is optimized according to the config. You will not get code repetition.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With