Reputation: 1123
I have one js file which needs to be put in the public directory and needs to add it in the final production build as a text/javascript
.
I have checked the options in vite config but couldn't find anything useful. The files I add contain a global JSON object and can be accessed directly.
To achieve this, I tried this solution.
vite.config.ts
import { fileURLToPath, URL } from "url";
import path from 'path';
// import test from "./src/assets/test.js"
import test from "./public/test.js"
import { defineConfig , loadEnv} from "vite";
import vue from "@vitejs/plugin-vue";
import { loadingScript } from 'vite-plugin-loading-script'
export default defineConfig(({ command, mode }) => {
// Load env file based on `mode` in the current working directory.
// Set the third parameter to '' to load all env regardless of the `VITE_` prefix.
const env = loadEnv(mode, process.cwd(), '')
return {
// vite config
define: {
__APP_ENV__: JSON.stringify(env.VITE_REDIRECT_URL),
__TEST__: test,
},
plugins: [vue()],
server: {
hmr: {
overlay: false,
},
},
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
build: {
// rollupOptions: {
// external: ['__APP_ENV__'],
// output: {
// globals: {
// __APP_ENV__: JSON.stringify(env.VITE_REDIRECT_URL),
// }
// }
// }
}
}
});
test.js
export default {
REDIRECT_URL: "https://example.com/",
API_URL: "https://example.com/",
};
with the above changes, I got the console.log('__TEST__', __TEST__)
as expected JSON object but it doesn't work with the production build.
Upvotes: 1
Views: 5340
Reputation: 51
If I understood you correctly, you want to inject the vars REDIRECT_URL
and API_URL
into your app. First off, in our case we stopped using .env
, process.env
, etc, as it didn't work in the production build (perhaps we were using it incorrectly). Our app uses Vite 3.
The solution for us was to mix different techniques that could solve both scenarios:
Let's use the API_URL
as an example. Change your test.js
file to look like this:
test.js
window.__RUNTIME_CONFIG__ = {
API_URL: 'https://example.com/'
};
Your
test.js
file should be inside thepublic
folder.
What we are doing here, is to inject a new global object to the window called __RUNTIME_CONFIG__
(you could name it whatever you want).
Now make sure that you are including this file in your index.html:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="test.js"></script>
...
</head>
...
</html>
Simple enough right?
At this point your problem (in its basic form) should be solved but let's be honest, that's not fancy at all and there's nothing magical there. We could add some extra sauce:
If you would like this to be typed-safe you could add a globals.ts
file with the following content:
export {};
declare global {
interface Window {
__RUNTIME_CONFIG__: {
API_URL: string;
};
__PACKAGE_JSON_VERSION__: string;
}
}
And an envVars.ts
file with the following content:
export const envVars = {
getVars: () => {
if (!window.__RUNTIME_CONFIG__.API_URL) {
throw new Error('Environment variables misconfiguration.');
}
return {
API_URL: window.__RUNTIME_CONFIG__.API_URL
};
}
};
const { API_URL } = envVars.getVars();
export { API_URL };
Your folder structure will end up something like this:
Now you can use it something like this:
import axios from 'axios';
import { API_URL } from 'src/domain';
export const axiosBase = axios.create({
baseURL: API_BASE_URL
});
Now things start to get a little more tricky but before we dive into the juicy stuffs, I want to make things clear first:
There's no such thing as "environment" or "env vars" when we deal with client side applications. The "environment" is each of your users using their own devices. We'll use the word "environment" for the sake of simplicity and just to mention different types of servers (local environment, QA environment, production environment, etc).
In our case we use runtime env configurations (runtime-env.js
), for you it would be your test.js
file. Create one test-{env}.js
per environment and locate them inside your public folder. Adjust your test-{env}.js
files accordingly:
Now you will face 2 scenarios:
For scenario 1. modify your package.json
file and add the following script:
"predev": "bash -c \"cp public/runtime-env-local.js public/runtime-env.js\"",
assuming you start your project using yarn dev
. If you use the yarn start
command instead, simply change predev
to prestart
.
For scenario 2. the answer is: it depends, but the main idea is to be able to copy one of the test-{env}.js
files into test.js
because that is what your index.html
file is expecting. We use docker for all of our applications, so what we did was to create a .sh
bash file to do that before the CMD command is executed.
env.sh
#!/bin/bash
cp "test-$RUNTIME_ENV.js" "test.js"
Dockerfile
FROM nginx:stable-alpine
...
# Copy .env file and shell script to container
COPY env.sh /usr/share/nginx/html/env.sh
# Make the shell script executable
RUN chmod +x /usr/share/nginx/html/env.sh
CMD ["/bin/bash", "-c", "/usr/share/nginx/html/env.sh && nginx -g \"daemon off;\""]
Then we spin up our docker like this:
docker build -t my-awesome-app .
docker run -d -p 5174:80 -e RUNTIME_ENV=production --name my-awesome-app my-awesome-app
Hope this helps someone else in the future.
Upvotes: 0
Reputation: 17
maybe you can try including the js file to the html in the public directory
Upvotes: 0