Reputation: 5566
I have a simple app in which require a user to provide certain pieces of information as follows.
Please provide your domain .
user: www.google.com
Please provide your vast URL.
user: www.vast.xx.com
Please select position. a) Bottom left. b) Bottom right.
user: b) Bottom right
After the user provides these pieces of information the button generate code
appears, the user clicks to generate code. He gets the following code.
(function (w,d,s,o,f,js,fjs) {
w['JS-Widget']=o;w[o] = w[o] || function () { (w[o].q = w[o].q || []).push(arguments) };
js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
js.id = o; js.src = f; js.async = 1; fjs.parentNode.insertBefore(js, fjs);
}(window, document, 'script', 'mw', 'www.mywebisite.com/widget123.js'));
mw('init', { someConfiguration: 448 });
mw('message', 'x');
</script>
Here is my full webpack config file: webpack config
With this script, a user can use it on his website, the important thing here to note is www.mywebisite.com/widget123.js
this is bundled js file generated by webpack as follow.
Here is part of my code I use to generate bundled js files using webpack by running a command npm run build
const HtmlWebpackPlugin = require('html-webpack-plugin');
// ...
return [{
entry: './src/main.js',
plugins: [
new HtmlWebpackPlugin({ title: 'Caching' }),
],
output: {
**filename: 'widget.[contenthash].js',**
path: path.resolve(bundleOutputDir),
}
}]
To generate the bundled js file each time a user generates a new code I need to run npm run build
to do that I am using WebSockets to send a command to the server as follows.
HTML (client)
<html>
<body>
<button onClick="sendCommands()"> Generate Code</button>
</body>
<script>
const ws = new WebSocket('ws://localhost:9898/');
function sendCommands(){
ws.onopen = function() {
console.log('WebSocket Client Connected');
ws.send('npm run build');
};
}
ws.onmessage = function(e) {
console.log("Received: '" + e.data + "'");
};
</script>
</html>
Here is Server.js
const http = require('http');
const WebSocketServer = require('websocket').server;
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const server = http.createServer();
server.listen(9898);
const wsServer = new WebSocketServer({
httpServer: server
});
wsServer.on('request', function(request) {
const connection = request.accept(null, request.origin);
connection.on('message', function(message) {
console.log(message.utf8Data);
const { stdout, stderr } = await exec(message.utf8Data);
console.log('stdout:', stdout);
console.log('stderr:', stderr);
connection.sendUTF('Hi this is WebSocket server!');
});
connection.on('close', function(reasonCode, description) {
console.log('Client has disconnected.');
});
});
Problem :
Now let assume I have 4 users in which each of them have generated their own js bundle file in dist folder I will have four files like this:
widget4321.js, widget3345.js, widget1123.js, widget4321.js
Assume I have changed the color of my widget, How do I update these files using webpack?.
Note: please be free to provide another solution if you have one thanks.
Upvotes: 4
Views: 1398
Reputation: 3558
Because you are using 'widget.[contenthash].js'
content hash and it will change every time content of the file is changed so you can not associate a file with user
What you can do is instead of using contenthash
you could do something like this
{
output {
filename: `widget.${someUserSpecificId}.js`
...
...
}
}
now the question is how you will get to pass the someUserSpecificId
in configuration. To do that you can use Webpack's environment-options
now in webpack configuration if you export a function instead of object like this
function (env, arg) {
return {
...
...
output: {
filename: `widget.${env.someUserSpecificId}.js`
...
...
}
}
and now you can pass the env.someUserSpecificId
with cli option like
webpack --env.someUserSpecificId=foo
now you can update any bundle for any user as you like
NOTE be aware that you don't use actual user id in filename because it will be exposed to client instead generate some random id for each user which is ok to expose on client and unique to each user
UPDATE method above described is good for updating some specific bundle but if you want to update all the bundle in one go you have to tweak the logic a bit
Instead of passing the someUserSpecificId
from command line argument you can do this
const usersIdArray = ['userId1', 'userId2', ...otherUsersId];
const webpackConfig = userIdArray.map(someUserSpecificId => {
return {
...
...
output: {
filename: `widget.${someUserSpecificId}.js`
...
...
}
};
});
module.exports = webpackConfig;
what it will do is it will give you a array of multiple webpack config and you can pass that array directly to webpack and webpack will update all the files according to respective config see exporting multiple configuration
Note if you have very large array of users please batch your task in small segment
Other Optimization idea because you are running this task on your server it would be good to think of some optimization to reduce repetitive task one idea i have right now is you can build bundles in two part 1. will contain user specific config 2. will contain your code
so if user change his configuration you have to build only that part and if you change your configuration then also you have to build that only once because your common code will be same for all users ( like theme )
and when you creating final bundle just combine user-specific configuration with your code that way you can reduce repetitive task and it would be a lot faster
Upvotes: 1
Reputation: 1748
It might be easier for you to have a single widget file (generated by you with the default configuration) and use the user-provided information as parameters.
domainName: www.google.com vastUrl: www.vast.xx.com position: Bottom right
(function (w,d,s,o,f,js,fjs) {
w['JS-Widget']=o;w[o] = w[o] || function () { (w[o].q = w[o].q || []).push(arguments) };
js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
js.id = o; js.src = f; js.async = 1; fjs.parentNode.insertBefore(js, fjs);
}(window, document, 'script', 'mw', 'www.mywebisite.com/widget123.js'));
mw('init', {
someConfiguration: 448,
domainName: 'www.google.com',
vastUrl: 'www.vast.xx.com',
position: 'bottom right'
});
mw('message', 'x');
</script>
Afterward, use the variables in your widget.
Then, updating the color of the widget will affect all the installed widgets and will keep the user's configuration.
Upvotes: 3