Plugin system for apps compiled using Webpack - reactjs

For the context: I'm developing my own product using Symfony on the back-end and react/react-router on the front-end, which is tied together by Webpack. I'm planning to divide my app into "extensions", so I would have "core" bundle and multiple different extending bundles around it (which would be sets of additional features for my product).
Now, I would like for my front-end to be as extensible as my back-end. I would like to be able to add new React components with my extending bundles to the existing "core" set of components in my "CoreBundle".
However, it seems like the Webpack is encapsulating everything too tightly to be able to produce that kind of a plugin system. Is it possible to have multiple bundles that would have separate Webpack configurations, but their JavaScript would be interconnected in a way that would allow for developing of a plugin system? The goal is being able to develop JS of one Bundle independently but at the same time being able to use some already compiled JS resources from another Bundle in the process.

I think you should be able to achieve this using the DllPlugin and the DllReferencePlugin
The DllPlugin is used in a separate webpack config to create a dll
only bundle. It also creates a manifest.json file which is used by the
DllReferencePlugin to map dependencies.
Refer to the detailed documentation at
https://webpack.js.org/plugins/dll-plugin/
In my case, I use this to combine all vendor libraries (React, Flux, etc) in one build and then use that as a reference in my Other Webpack Config which bundles all my React components etc. but references React and other libraries using the DllReferencePlugin.
My webpack.dll.js config file:
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: {
libs: [path.join(__dirname, "common", "lib.js")]
},
output: {
path: path.join(__dirname, "dist", "dll"),
filename: "[name].dll.js",
library: "[name]"
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, "dll", "[name]-manifest.json"),
name: "[name]",
context: path.resolve(__dirname, "common")
}),
]
};
And then in my main webpack.config.js, I use the reference plugin.
new webpack.DllReferencePlugin({
context: path.resolve(__dirname, "common"),
manifest:require('./dll/libs-manifest.json')
})
Depending upon how you want to split your code, you can create multiple Dlls, each with a separate webpack config as per your requirements. And then refer the dll's as per your requirements in different other webpack bundles.

Related

How to create multiple entry points(index.js) for a single react application?

I want to create two different builds for a single application. When I do an npm run build, it runs webpack and generates a build, and injects that build into the index.html file. What I ideally want to do is tell webpack to create one build from index.js and another build from index2.js. How do I achieve this? Looked into module federation, but wasn't able to figure out how to do this in a single application.
You can do this settings in webpack.config.js.
module.exports = {
entry: {
bundle1: "path for index1.js",
bundle2: "path for index2.js"
},
output: {
// `filename` provides a template for naming your bundles (remember to use `[name]`)
filename: '[name].js'
publicPath: 'Path for saving directory'
}};

Shipping a React application as a singular JS file

I have an application created with create-react-app which needs to be shipped as a singular .js file, complete with its components and CSS style sheets. How can it be done? Without ejecting, if possible. The standard npm run build command only provides source code split into chunks.
Tried solving this issue with with react-rewire-app, but the build failed to complete.
My config-override.js is as follows:
const path = require('path');
module.exports = function override(config, env) {
config.entry = {
'my-app': './src/index.js'
}
config.module.output = {
path: path.resolve(__dirname, '../target/classes/static/'),
filename: '[name].js',
publicPath: '/'
}
return config
}
``
You're looking to make a widget or a library, likely, not an application, so CRA is the wrong tool. CRA is a tool for applications, where you definitely don't want everything bundled into a single file like you're asking for, as that would be very poor user experience.
For library/widget bundlers, I'd take a look at something like Microbundle: https://github.com/developit/microbundle. Should be very little config.
That being said, you cannot include CSS style sheets in JS. You can't even import them into JS. You need to ship them along with your JS and let your user handle importing it through HTML or what have you.

Include only used imports in the packaged bundle ReactJS

I wanna use only one component from Material Ui library . I know i can import only one component using ES6 import but does webpack treeshake and remove other components from the library or include them in production .
Please help me.
Webpack from v2 onwards eliminates unused exports in two steps:
First, all ES6 module files are combined into a single bundle file in which exports that were not imported anywhere are not exported, anymore.
Second, the bundle is minified, while eliminating dead code. Therefore, entities that are neither exported nor used inside their modules do not appear in the minified bundle. Without the first step, dead code elimination would never remove exports.
Unused exports can only be reliably detected at build time if the module system has a static structure.
Webpack doesn't perform tree-shaking by itself. It relies on third party tools like UglifyJS to perform actual dead code elimination.
To do that, you would install it using
npm install --save-dev uglifyjs-webpack-plugin
And then adding it into the config:
webpack.config.js
const path = require('path');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new UglifyJSPlugin()
]
};
So when you add this config, your unused exports are not longer present in the minified build.
Webpack 5 comes with terser-webpack-plugin out of the box, hence you can just import it and configure as you wish.

How to point assets and html angular templates folder after building angularjs with webpack?

i am new to webpack, i have configured webpack to a working condition where my index.html file and budle.js file comes to /dist folder. iam aware that i can build css files too but for now i want to build js and run the app. please check the attached images for better understanding of the directory structure and the webpack build configuration.
My doubt is that if i run app from dist folder i would lose all the path of angular templates and image paths etc. how can i overcome this situation? any help is appreciated.
First of all, you need to know that the goal is to have a fully runnable stand alone application inside ./dist/ after build. All sourcefiles which are needed to run your application should be placed there. In that way you will be able to distribute your application by copy/upload/or-what-ever based on your ./dist/ directory. All other directories in your project are just for development. Those will be not a part of your distribution package.
Wrong approach: Trying to change the include path's in your application.
You need to copy or concat your sourcefiles (static files) into your distribution folder. I realy don't know why your views/templates are not stored in ./app/assets/ and not in ./app/views/ because ./app/views/ should be the correct path to store your views. Well, you need to copy your static sourcefiles. For example: You could use copy-webpack-plugin.
Your webpack config could look like this in the end:
var CopyWebpackPlugin = require('copy-webpack-plugin');
var path = require('path');
module.exports = {
context: path.join(__dirname, 'app'),
devServer: {
// This is required for older versions of webpack-dev-server
// if you use absolute 'to' paths. The path should be an
// absolute path to your build destination.
outputPath: path.join(__dirname, 'dist')
},
plugins: [
new CopyWebpackPlugin([
{
from: 'assets/**/*',
to: 'assets/'
},
{
from: 'views/**/*',
to: 'views/'
},
], {
ignore: [
],
// By default, we only copy modified files during
// a watch or webpack-dev-server build. Setting this
// to `true` copies all files.
copyUnmodified: true
})
]
};

React with Webpack - package a module for use in Dynamic loading in another site

I'm using Webpack as our build/bundler for an application using a standard React/Redux/etc.
We have a requirement to build out custom components that can be loaded dynamically into the main application. This would require that the component is created OUTSIDE the main development so would not be involved in the main app build. The ideal solution would be to build out the components in their own side projects, bundle up (since they will have imports/require, etc) and spit out a bundle.js file that is only that component (could be multiple components merged together). Then we'd like to be able to take that file and dynamically load it in the main application dynamically.
I understand how code splitting works with webpack to a certain degree which we use in our main project. I've also been able to successfully import SIMPLE components externally I built out externally. The problem is that these external components can get pretty hefty so using a build/bundler to put it all together in one package would be ideal. I have no idea how to go about building components externally from the main project, bundle up using webpack to merge in all of the goodies into one package and inject that new bundled component which is typically wrapped in webpackjsonp and all the other runtime stuff.
Has anybody else been able to do something crazy like this?
Thanks!
EDIT
I've been able to successfully build a silo component in it's own project using webpack and dynamically loading that into a different running application bundled with webpack by using the Output.Library options as described here
Below is the sample config I used for testing a custom react component called TestMe located inside the index.js file of the test folder.
module.exports = {
entry: {
developer: "./test"
},
output: {
path: path.join(__dirname, "dist", "static", "developer"),
filename: "MyLibrary.[name].js",
library: ["MyLibrary", "[name]"],
libraryTarget: "var"
},
externals: {
'react': 'React'
, 'react-dom': 'ReactDOM'
, 'react-dom/server': 'ReactDOMServer'
, 'react/lisb/ReactTransitionGroup': 'React.addons.TransitionGroup'
, 'react/lib/ReactCSSTransitionGroup': 'React.addons.CSSTransitionGroup'
}, ...
When imported in you will have access to the TestMe component as a global variable MyLibrary.developer.TestMe (or MyLibrary.developer.default depending on how you exported the component). The externals are there to keep Webpack from including those in the final bundle which was already included in the main application. Otherwise you're going to get a really big nasty bundle file. Check out LibraryTarget if you rather have UMD, etc.
Moral of the story here is "when all else fails, read the docs again".

Resources