webpack.config.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. const path = require("path");
  2. const HtmlWebpackPlugin = require("html-webpack-plugin");
  3. const webpack = require("webpack");
  4. const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
  5. const dotenv = require("dotenv");
  6. const BundleAnalyzerPlugin =
  7. require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
  8. const TerserPlugin = require("terser-webpack-plugin");
  9. module.exports = () => {
  10. let envPath = ".env";
  11. if (process.env.ENV_FILE !== "") {
  12. envPath = process.env.ENV_FILE;
  13. }
  14. console.log(`using envfile from path ${envPath}`);
  15. let env = dotenv.config({ path: envPath }).parsed;
  16. console.log(env);
  17. if (!env) {
  18. env = process.env;
  19. }
  20. const envKeys = Object.keys(env).reduce((prev, next) => {
  21. const varName = `process.env.${next}`;
  22. if (typeof env[next] !== "string") return prev;
  23. if (env[next].toLowerCase() === "true") {
  24. prev[varName] = true;
  25. } else if (env[next].toLowerCase() === "false") {
  26. prev[varName] = false;
  27. } else {
  28. prev[varName] = JSON.stringify(env[next]);
  29. }
  30. return prev;
  31. }, {});
  32. // Check first the env file and if it's empty, check out the node env of the process.
  33. let isDevelopment = env.NODE_ENV !== "production";
  34. if (process.env.NODE_ENV !== env.NODE_ENV) {
  35. isDevelopment = process.env.NODE_ENV !== "production";
  36. }
  37. let htmlPluginOpts = {
  38. template: path.resolve(__dirname, "src", "index.html"),
  39. };
  40. if (env.IS_HOSTED) {
  41. htmlPluginOpts = {
  42. template: path.resolve(__dirname, "src", "hosted.index.html"),
  43. intercomAppId: `${env.INTERCOM_APP_ID}`,
  44. hotjarId: `${env.HOTJAR_ID}`,
  45. intercomSrc: `${process.env.INTERCOM_SRC}`,
  46. segmentWriteKey: `${process.env.SEGMENT_WRITE_KEY}`,
  47. segmentKey: `${process.env.SEGMENT_PUBLIC_KEY}`,
  48. };
  49. }
  50. /**
  51. * @type {webpack.Configuration}
  52. */
  53. const config = {
  54. entry: [
  55. "core-js/modules/es.promise",
  56. "core-js/modules/es.array.iterator",
  57. "./src/index.tsx",
  58. ],
  59. target: "web",
  60. mode: isDevelopment ? "development" : "production",
  61. devtool: "source-map",
  62. module: {
  63. rules: [
  64. {
  65. test: /\.(ts|tsx|mjs|js|jsx)$/,
  66. exclude: /node_modules\/(?!(chart.js|react-chartjs-2)\/).*/,
  67. use: [
  68. {
  69. loader: require.resolve("babel-loader"),
  70. options: {
  71. plugins: [
  72. isDevelopment && require.resolve("react-refresh/babel"),
  73. ].filter(Boolean),
  74. },
  75. },
  76. ],
  77. },
  78. {
  79. test: /\.(mjs|js)$/,
  80. include: /node_modules/,
  81. type: "javascript/auto",
  82. },
  83. {
  84. test: /\.mjs$/,
  85. use: [
  86. {
  87. loader: require.resolve("babel-loader"),
  88. options: {
  89. plugins: [
  90. isDevelopment && require.resolve("react-refresh/babel"),
  91. ].filter(Boolean),
  92. },
  93. },
  94. ],
  95. },
  96. {
  97. enforce: "pre",
  98. test: /\.(ts|tsx|mjs|js|jsx)$/,
  99. loader: "source-map-loader",
  100. },
  101. {
  102. test: /\.(png|svg|jpg|gif|mp3)$/,
  103. use: ["file-loader"],
  104. },
  105. // {
  106. // test: /\.css$/i,
  107. // loader: "css-loader",
  108. // options: {
  109. // import: true,
  110. // },
  111. // },
  112. {
  113. test: /\.css$/i,
  114. use: [
  115. { loader: "style-loader", options: { injectType: "linkTag" } },
  116. { loader: "file-loader" },
  117. ],
  118. },
  119. {
  120. test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
  121. use: [
  122. {
  123. loader: "file-loader",
  124. options: {
  125. name: "[name].[ext]",
  126. outputPath: "fonts/",
  127. },
  128. },
  129. ],
  130. },
  131. ],
  132. },
  133. resolve: {
  134. modules: [path.resolve(__dirname, "src"), "node_modules"],
  135. extensions: ["*", ".tsx", ".ts", ".js", ".jsx", ".json"],
  136. },
  137. output: {
  138. filename: "bundle.js",
  139. path: path.resolve(__dirname, "build"),
  140. publicPath: "/",
  141. },
  142. devServer: {
  143. historyApiFallback: true,
  144. disableHostCheck: true,
  145. host: "0.0.0.0",
  146. port: env.DEV_SERVER_PORT || 8080,
  147. hot: true,
  148. },
  149. plugins: [
  150. new HtmlWebpackPlugin(htmlPluginOpts),
  151. new webpack.DefinePlugin(envKeys),
  152. isDevelopment && new ReactRefreshWebpackPlugin(),
  153. ].filter(Boolean),
  154. };
  155. if (!isDevelopment) {
  156. config.optimization = {
  157. minimize: true,
  158. minimizer: [
  159. new TerserPlugin({
  160. test: /\.(ts|tsx|mjs|js|jsx)$/,
  161. terserOptions: {
  162. parse: {
  163. // We want terser to parse ecma 8 code. However, we don't want it
  164. // to apply minification steps that turns valid ecma 5 code
  165. // into invalid ecma 5 code. This is why the `compress` and `output`
  166. ecma: 8,
  167. },
  168. compress: {
  169. ecma: 5,
  170. warnings: false,
  171. inline: 2,
  172. },
  173. mangle: {
  174. // Find work around for Safari 10+
  175. safari10: true,
  176. },
  177. output: {
  178. ecma: 5,
  179. comments: false,
  180. ascii_only: true,
  181. },
  182. },
  183. // Use multi-process parallel running to improve the build speed
  184. parallel: true,
  185. }),
  186. ],
  187. };
  188. }
  189. if (env.ENABLE_ANALYZER) {
  190. config.plugins.push(new BundleAnalyzerPlugin());
  191. }
  192. if (env.ENABLE_PROXY) {
  193. if (!env.API_SERVER) {
  194. throw new Error(
  195. "API_SERVER is not present on .env! Please setup the api server url if you want the proxy to work! API_SERVER example: http://localhost:8080"
  196. );
  197. }
  198. config.devServer.proxy = {
  199. "/api": {
  200. logLevel: "debug",
  201. target: env.API_SERVER, // target host
  202. changeOrigin: true, // needed for virtual hosted sites
  203. ws: true, // proxy websockets
  204. },
  205. };
  206. }
  207. return config;
  208. };