diff --git a/Dockerfile b/Dockerfile index fdbd4c0a..62d348c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,7 +26,7 @@ COPY server . RUN cp .env.sample .env COPY --from=client-builder /app/build public -COPY --from=client-builder /app/build/index.html views +COPY --from=client-builder /app/build/index.html views/index.ejs VOLUME /app/public/user-avatars VOLUME /app/public/project-background-images diff --git a/client/config-overrides.js b/client/config-overrides.js new file mode 100644 index 00000000..21c3b646 --- /dev/null +++ b/client/config-overrides.js @@ -0,0 +1,47 @@ +const fs = require('fs'); +const path = require('path'); + +const BASE_URL_PLACEHOLDER = 'BASE_URL_PLACEHOLDER'; + +const replaceInFile = (file, search, replace) => { + fs.readFile(file, 'utf8', (err, data) => { + if (err) { + throw new Error(`${err}`); + } + const res = data.replaceAll(search, replace); + fs.writeFile(file, res, 'utf8', (err) => { + if (err) { + throw new Error(`${err}`); + } + }); + }); +}; + +const replaceBaseUrl = (compiler) => { + compiler.hooks.assetEmitted.tap("Test", (file, info) => { + if (info.content.indexOf(BASE_URL_PLACEHOLDER) >= 0) { + if (/\.css$/.exec(info.targetPath)) { + // For CSS 'url(...)' import we can use relative import + const relPath = path.relative(path.dirname(info.targetPath), info.outputPath); + replaceInFile(info.targetPath, BASE_URL_PLACEHOLDER, `${relPath}/`); + } else if (/\.js$/.exec(info.targetPath)) { + // For JS 'import ... from "some-asset"' we can get the variable injected in the window object + replaceInFile(info.targetPath, `"${BASE_URL_PLACEHOLDER}"`, '`${window.BASE_URL}/`'); + } else if (/index\.html$/.exec(info.targetPath)) { + // For the main html file, we set a placeholder for sails to inject the correct value as runtime + replaceInFile(info.targetPath, BASE_URL_PLACEHOLDER, '<%= BASE_URL %>'); + } + } + }); +}; + +module.exports = function override(config, env) { + config.plugins.forEach(plugin => { + if (plugin.constructor.name === 'InterpolateHtmlPlugin') { + plugin.replacements.PUBLIC_URL = BASE_URL_PLACEHOLDER; + } + }); + config.plugins.push({ apply: replaceBaseUrl }); + config.output.publicPath = BASE_URL_PLACEHOLDER; + return config; +}; diff --git a/client/package-lock.json b/client/package-lock.json index 915cfd50..f69a43cd 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -63,6 +63,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "jest-enzyme": "^7.1.2", "prettier": "2.7.1", + "react-app-rewired": "^2.2.1", "react-test-renderer": "^17.0.2" } }, @@ -18665,6 +18666,30 @@ "node": ">=14" } }, + "node_modules/react-app-rewired": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz", + "integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==", + "dev": true, + "dependencies": { + "semver": "^5.6.0" + }, + "bin": { + "react-app-rewired": "bin/index.js" + }, + "peerDependencies": { + "react-scripts": ">=2.1.3" + } + }, + "node_modules/react-app-rewired/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/react-beautiful-dnd": { "version": "13.1.0", "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz", @@ -38717,6 +38742,23 @@ "whatwg-fetch": "^3.6.2" } }, + "react-app-rewired": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz", + "integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==", + "dev": true, + "requires": { + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, "react-beautiful-dnd": { "version": "13.1.0", "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz", diff --git a/client/package.json b/client/package.json index f4f05ae7..104986f3 100755 --- a/client/package.json +++ b/client/package.json @@ -2,11 +2,11 @@ "name": "planka-client", "private": true, "scripts": { - "build": "react-scripts build", + "build": "react-app-rewired build", "eject": "react-scripts eject", "lint": "eslint --ext js,jsx src", - "start": "react-scripts start", - "test": "react-scripts test" + "start": "react-app-rewired start", + "test": "react-app-rewired test" }, "browserslist": { "production": [ @@ -120,6 +120,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "jest-enzyme": "^7.1.2", "prettier": "2.7.1", + "react-app-rewired": "^2.2.1", "react-test-renderer": "^17.0.2" } } diff --git a/client/public/index.html b/client/public/index.html index e8955e7e..fc7327a7 100755 --- a/client/public/index.html +++ b/client/public/index.html @@ -26,6 +26,7 @@ -->