mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-12 17:49:49 -06:00
fix: Make js assets cachable (#3337)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com> Co-authored-by: Anshuman Pandey <54475686+pandeymangg@users.noreply.github.com>
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -58,3 +58,5 @@ packages/lib/uploads
|
||||
# Vite Timestamps
|
||||
*vite.config.*.timestamp-*
|
||||
|
||||
# js compiled assets
|
||||
apps/web/public/js
|
||||
|
||||
@@ -43,7 +43,7 @@ All you need to do is copy a `<script>` tag to your HTML head, and that’s abou
|
||||
var apiHost = "https://app.formbricks.com";
|
||||
var environmentId = "<your-environment-id>";
|
||||
var userId = "<your-user-id>"; //optional
|
||||
var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=apiHost+"/api/packages/js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: environmentId, apiHost: apiHost, userId: userId})},500)}();
|
||||
var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=apiHost+"/js/formbricks.umd.cjs";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: environmentId, apiHost: apiHost, userId: userId})},500)}();
|
||||
</script>
|
||||
<!-- END Formbricks Surveys -->
|
||||
```
|
||||
|
||||
@@ -34,7 +34,7 @@ export const OnboardingSetupInstructions = ({
|
||||
var apiHost = "${webAppUrl}";
|
||||
var environmentId = "${environmentId}";
|
||||
var userId = "testUser";
|
||||
var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=apiHost+"/api/packages/js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: environmentId, apiHost: apiHost, userId: userId})},500)}();
|
||||
var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=apiHost+"/js/formbricks.umd.cjs";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: environmentId, apiHost: apiHost, userId: userId})},500)}();
|
||||
</script>
|
||||
<!-- END Formbricks Surveys -->
|
||||
`;
|
||||
@@ -44,7 +44,7 @@ export const OnboardingSetupInstructions = ({
|
||||
!function(){
|
||||
var apiHost = "${webAppUrl}";
|
||||
var environmentId = "${environmentId}";
|
||||
var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=apiHost+"/api/packages/js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: environmentId, apiHost: apiHost})},500)}();
|
||||
var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src=apiHost+"/js/formbricks.umd.cjs";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: environmentId, apiHost: apiHost})},500)}();
|
||||
</script>
|
||||
<!-- END Formbricks Surveys -->
|
||||
`;
|
||||
|
||||
@@ -122,7 +122,7 @@ if (typeof window !== "undefined") {
|
||||
</p>
|
||||
<CodeBlock language="js">{`<!-- START Formbricks Surveys -->
|
||||
<script type="text/javascript">
|
||||
!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="${webAppUrl}/api/packages/js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: "${environmentId}", apiHost: "${window.location.protocol}//${window.location.host}"})},500)}();
|
||||
!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="${webAppUrl}/js/formbricks.umd.cjs";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: "${environmentId}", apiHost: "${window.location.protocol}//${window.location.host}"})},500)}();
|
||||
</script>
|
||||
<!-- END Formbricks Surveys -->`}</CodeBlock>
|
||||
<h4>Step 2: Debug mode</h4>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// DEPRECATED - This file is deprecated and will be removed in the future
|
||||
// Deprecated since 22-03-2024
|
||||
// This endpoint has been deprecated. Please use the new endpoint /api/packages/js instead.
|
||||
import { responses } from "@/app/lib/api/response";
|
||||
import { WEBAPP_URL } from "@formbricks/lib/constants";
|
||||
|
||||
export const GET = async () => {
|
||||
try {
|
||||
return responses.goneResponse(
|
||||
"This endpoint has been deprecated. Please use the new endpoint /api/packages/<package-name>",
|
||||
{
|
||||
"x-deprecated": "true",
|
||||
"x-deprecated-date": "22-03-2024",
|
||||
"x-deprecated-redirect": `${WEBAPP_URL}/api/packages/js`,
|
||||
},
|
||||
true
|
||||
);
|
||||
} catch (error) {
|
||||
return responses.internalServerErrorResponse("this endpoint is not available");
|
||||
}
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
import { responses } from "@/app/lib/api/response";
|
||||
import fs from "fs/promises";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
export const GET = async (_: NextRequest, { params }: { params: { package: string } }) => {
|
||||
let path: string;
|
||||
const packageRequested = params.package;
|
||||
|
||||
switch (packageRequested) {
|
||||
case "js":
|
||||
path = `../../packages/js-core/dist/index.umd.cjs`;
|
||||
break;
|
||||
case "surveys":
|
||||
path = `../../packages/surveys/dist/index.umd.cjs`;
|
||||
break;
|
||||
default:
|
||||
return responses.notFoundResponse(
|
||||
"package",
|
||||
packageRequested,
|
||||
true,
|
||||
"public, max-age=600, s-maxage=600, stale-while-revalidate=600, stale-if-error=600" // 10 minutes cache for not found
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const packageSrcCode = await fs.readFile(path, "utf-8");
|
||||
return new Response(packageSrcCode, {
|
||||
headers: {
|
||||
"Content-Type": "application/javascript",
|
||||
"Cache-Control":
|
||||
"public, max-age=3600, s-maxage=604800, stale-while-revalidate=3600, stale-if-error=3600",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
if (error.code === "ENOENT") {
|
||||
return responses.notFoundResponse(
|
||||
"package",
|
||||
packageRequested,
|
||||
true,
|
||||
"public, max-age=600, s-maxage=600, stale-while-revalidate=600, stale-if-error=600" // 10 minutes cache for file not found errors
|
||||
);
|
||||
} else {
|
||||
console.error("Error reading file:", error);
|
||||
return responses.internalServerErrorResponse(
|
||||
"internal server error",
|
||||
true,
|
||||
"public, max-age=600, s-maxage=600, stale-while-revalidate=600, stale-if-error=600" // 10 minutes cache for internal errors
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -163,17 +163,61 @@ const nextConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
source: "/js/(.*)",
|
||||
headers: [
|
||||
{
|
||||
key: "Cache-Control",
|
||||
value: "public, max-age=3600, s-maxage=604800, stale-while-revalidate=3600, stale-if-error=3600",
|
||||
},
|
||||
{
|
||||
key: "Content-Type",
|
||||
value: "application/javascript; charset=UTF-8",
|
||||
},
|
||||
{
|
||||
key: "Access-Control-Allow-Origin",
|
||||
value: "*",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// headers for /api/packages/(.*) -- the api route does not exist, but we still need the headers for the rewrites to work correctly!
|
||||
{
|
||||
source: "/api/packages/(.*)",
|
||||
headers: [
|
||||
{
|
||||
key: "Cache-Control",
|
||||
value: "public, max-age=3600, s-maxage=604800, stale-while-revalidate=3600, stale-if-error=3600",
|
||||
},
|
||||
{
|
||||
key: "Content-Type",
|
||||
value: "application/javascript; charset=UTF-8",
|
||||
},
|
||||
{
|
||||
key: "Access-Control-Allow-Origin",
|
||||
value: "*",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
},
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: "/api/packages/website",
|
||||
destination: "/api/packages/js",
|
||||
destination: "/js/formbricks.umd.cjs",
|
||||
},
|
||||
{
|
||||
source: "/api/packages/app",
|
||||
destination: "/api/packages/js",
|
||||
destination: "/js/formbricks.umd.cjs",
|
||||
},
|
||||
{
|
||||
source: "/api/packages/js",
|
||||
destination: "/js/formbricks.umd.cjs",
|
||||
},
|
||||
{
|
||||
source: "/api/packages/surveys",
|
||||
destination: "/js/surveys.umd.cjs",
|
||||
},
|
||||
{
|
||||
source: "/api/v1/client/:environmentId/website/environment",
|
||||
|
||||
40
packages/copyCompiledAssetsPlugin/vite.config.ts
Normal file
40
packages/copyCompiledAssetsPlugin/vite.config.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import fs from "fs-extra";
|
||||
import path from "path";
|
||||
import { Plugin, ResolvedConfig } from "vite";
|
||||
|
||||
interface CopyCompiledAssetsPluginOptions {
|
||||
filename: string;
|
||||
distDir: string;
|
||||
}
|
||||
|
||||
export function copyCompiledAssetsPlugin(options: CopyCompiledAssetsPluginOptions): Plugin {
|
||||
let config: ResolvedConfig;
|
||||
|
||||
return {
|
||||
name: "copy-compiled-assets",
|
||||
apply: "build",
|
||||
|
||||
configResolved(_config) {
|
||||
config = _config;
|
||||
},
|
||||
|
||||
async writeBundle() {
|
||||
const outputDir = path.resolve(config.root, "../../apps/web/public/js");
|
||||
const distDir = path.resolve(config.root, options.distDir);
|
||||
|
||||
// Create the output directory if it doesn't exist
|
||||
fs.ensureDirSync(outputDir);
|
||||
console.log(`Ensured directory exists: ${outputDir}`);
|
||||
|
||||
// Copy files from distDir to outputDir
|
||||
const filesToCopy = fs.readdirSync(distDir);
|
||||
filesToCopy.forEach((file) => {
|
||||
const srcFile = path.resolve(distDir, file);
|
||||
const destFile = path.resolve(outputDir, file.replace("index", options.filename));
|
||||
fs.copyFileSync(srcFile, destFile);
|
||||
});
|
||||
|
||||
console.log(`Copied ${filesToCopy.length} files to ${outputDir} (${options.filename})`);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -61,8 +61,6 @@ export const fetchPersonState = async (
|
||||
const data = await response.json();
|
||||
const { data: state } = data;
|
||||
|
||||
console.log("Person state fetched", state);
|
||||
|
||||
const defaultPersonState: TJsPersonState = {
|
||||
expiresAt: new Date(new Date().getTime() + 1000 * 60 * 30), // 30 minutes
|
||||
data: {
|
||||
|
||||
@@ -268,7 +268,7 @@ const loadFormbricksSurveysExternally = (): Promise<typeof window.formbricksSurv
|
||||
resolve(window.formbricksSurveys);
|
||||
} else {
|
||||
const script = document.createElement("script");
|
||||
script.src = `${config.get().apiHost}/api/packages/surveys`;
|
||||
script.src = `${config.get().apiHost}/js/surveys.umd.cjs`;
|
||||
script.async = true;
|
||||
script.onload = () => resolve(window.formbricksSurveys);
|
||||
script.onerror = (error) => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { resolve } from "path";
|
||||
import { defineConfig } from "vite";
|
||||
import dts from "vite-plugin-dts";
|
||||
import webPackageJson from "../../apps/web/package.json";
|
||||
import { copyCompiledAssetsPlugin } from "../copyCompiledAssetsPlugin/vite.config";
|
||||
|
||||
const config = () => {
|
||||
return defineConfig({
|
||||
@@ -27,6 +28,7 @@ const config = () => {
|
||||
rollupTypes: true,
|
||||
bundledPackages: ["@formbricks/api", "@formbricks/types"],
|
||||
}),
|
||||
copyCompiledAssetsPlugin({ filename: "formbricks", distDir: resolve(__dirname, "dist") }),
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<script type="text/javascript">
|
||||
!(function () {
|
||||
var t = document.createElement("script");
|
||||
(t.type = "text/javascript"), (t.async = !0), (t.src = "http://localhost:3000/api/packages/js");
|
||||
(t.type = "text/javascript"), (t.async = !0), (t.src = "http://localhost:3000/js/formbricks.umd.cjs");
|
||||
var e = document.getElementsByTagName("script")[0];
|
||||
e.parentNode.insertBefore(t, e),
|
||||
setTimeout(function () {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@formbricks/js",
|
||||
"license": "MIT",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"description": "Formbricks-js allows you to connect your index to Formbricks, display surveys and trigger events.",
|
||||
"homepage": "https://formbricks.com",
|
||||
"repository": {
|
||||
|
||||
@@ -10,7 +10,7 @@ let isInitialized = false;
|
||||
// Load the SDK, return the result
|
||||
const loadFormbricksSDK = async (apiHostParam: string): Promise<Result<void>> => {
|
||||
if (!window.formbricks) {
|
||||
const res = await fetch(`${apiHostParam}/api/packages/js`);
|
||||
const res = await fetch(`${apiHostParam}/js/formbricks.umd.cjs`);
|
||||
|
||||
// Failed to fetch the app package
|
||||
if (!res.ok) {
|
||||
@@ -56,7 +56,6 @@ const loadFormbricksSDK = async (apiHostParam: string): Promise<Result<void>> =>
|
||||
const functionsToProcess: { prop: string; args: unknown[] }[] = [];
|
||||
|
||||
export const loadFormbricksToProxy = async (prop: string, ...args: unknown[]): Promise<void> => {
|
||||
console.log(args);
|
||||
// all of this should happen when not initialized:
|
||||
if (!isInitialized) {
|
||||
if (prop === "init") {
|
||||
|
||||
@@ -373,7 +373,7 @@ const renderHtml = (options: Partial<SurveyInlineProps> & { apiHost?: string }):
|
||||
}
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.src = "${options.apiHost ?? "http://localhost:3000"}/api/packages/surveys";
|
||||
script.src = "${options.apiHost ?? "http://localhost:3000"}/js/surveys.umd.cjs";
|
||||
script.async = true;
|
||||
script.onload = () => loadSurvey();
|
||||
script.onerror = (error) => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { resolve } from "path";
|
||||
import { defineConfig, loadEnv } from "vite";
|
||||
import dts from "vite-plugin-dts";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
import { copyCompiledAssetsPlugin } from "../copyCompiledAssetsPlugin/vite.config";
|
||||
|
||||
const config = ({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), "");
|
||||
@@ -26,7 +27,12 @@ const config = ({ mode }) => {
|
||||
fileName: "index",
|
||||
},
|
||||
},
|
||||
plugins: [preact(), dts({ rollupTypes: true }), tsconfigPaths()],
|
||||
plugins: [
|
||||
preact(),
|
||||
dts({ rollupTypes: true }),
|
||||
tsconfigPaths(),
|
||||
copyCompiledAssetsPlugin({ filename: "surveys", distDir: resolve(__dirname, "dist") }),
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export const SurveyInline = (props: Omit<SurveyInlineProps, "containerId">) => {
|
||||
|
||||
const loadSurveyScript: () => Promise<void> = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/packages/surveys");
|
||||
const response = await fetch("/js/surveys.umd.cjs");
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load the surveys package");
|
||||
|
||||
Reference in New Issue
Block a user