I am working on a Vue 3 web application that would be built and deployed for multiple customers. Each customer has its own title, logo, icon, etc.
What I need is to build the app for every customer with its specific information (let's say showing customer info in TheFooter.vue
component).
The important requirement is that when the app is going to be built for a customer, other customers' information MUST not be included in the final built files (I mean /dist
folder after running npm run build
) for privacy reasons.
The ways I tried:
- create a customers.js file and export an object like this:
const customers = {
CUSTOMER_A: {
title: 'Customer A',
logo: 'assets/customer_a_logo.png',
// other privacy related data
},
CUSTOMER_B: {
title: 'Customer B',
logo: 'assets/customer_b_logo.png',
// other privacy related data
}
export default const customer[process.env.VUE_APP_CURRENT_CUSTOMER]
then in the .env
file, create a VUE_APP_CURRENT_CUSTOMER
key with a value like CUSTOMER_A
, CUSTOMER_B
,...
And in TheFooter.vue
import customer data like this:
const customer = require('./customers.js').default
but this way I analyzed final built js in /dist
folder and other cusotmers' information were available.
Based on Vue CLI modes, for every customer create a
.env.customer_x
file and add customer-specific data in it, then when building app refers to the current customer with--mode
flag (e.g.vue-cli-service build --mode customer_x
). If customers are too many, we would end up with too many .env.customer_... files. (Any other caveats for this solution?)Create a json file (e.g. customers.json) and use it in
TheFooter.vue
like this:
import { process.env.VUE_APP_CURRENT_CUSTOMER } from './customers.json'
But it seems it is not possible to use variable inside import statement, and I need to use env variables (for ci/cd pipeline)
Is there any idea or best practices for this issue?
thanks in advance!
CodePudding user response:
It is basically a two step process to generate multiple builds.
Step 1: Custom script build
Write a custom build script that will programmatically invoke Webpack. Something like this:
// build.js file
const webpack = require('webpack');
// Your webpack.config.js should export a function instead of config.
const webpackConfig = require('./webpack.config.js');
// You can require this data from other `customers.js` file.
const customers = [
{ title: 'App 1' },
{ title: 'App2' }
];
customers.forEach((customer) => {
// Get webpack configuration for this customer.
const config = webpackConfig(customer);
// Invoke the webpack
webpack(config, (err) => {
/** Handle error here */
});
});
Your Webpack config would be wrapped in a callback function:
// webpack.config.js
module.exports = (customer) => {
// This function will be called from build.js file.
return {
entry: 'index.js',
output: {
// ...
}
// ...other webpack configuration
};
};
Step 2: Data injection
Use Webpack DefinePlugin
or some other means to inject this data into your actual JavaScript code. For the HTML pages, you can use webpack-html-plugin
that can also supports this feature using templates. You will need this to set <title>
and other HTML metadata for your customer's build.
new webpack.DefinePlugin({
CUSTOMER_DATA: JSON.stringify(customer)
});
Further, this build script should be optimized to deal with async
and also ensure that output directory is adjusted appropriately for each customer.
As an additional enhancement, Webpack also supports array configuration (multiple configurations) for creating multiple builds. You can use that as it provides parallel builds out-of-box and without needing separate build.js
file. I personally like to keep things separate/modular and thus explained that way.
The key to understand here is that in your actual code, you should nowhere import this customers.js
file. It is a build time thing and should be imported in build time scripts only.