]> Untitled Git - lemmy-ui.git/blob - webpack.config.js
Fix profile loading spinner
[lemmy-ui.git] / webpack.config.js
1 const webpack = require("webpack");
2 const path = require("path");
3 const MiniCssExtractPlugin = require("mini-css-extract-plugin");
4 const nodeExternals = require("webpack-node-externals");
5 const CopyPlugin = require("copy-webpack-plugin");
6 const RunNodeWebpackPlugin = require("run-node-webpack-plugin");
7 const merge = require("lodash.merge");
8 const { ServiceWorkerPlugin } = require("service-worker-webpack");
9
10 const banner = `
11   hash:[contentHash], chunkhash:[chunkhash], name:[name], filebase:[base], query:[query], file:[file]
12   Source code: https://github.com/LemmyNet/lemmy-ui
13   Created by dessalines
14   @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL v3.0
15   `;
16
17 function getBase(env, mode) {
18   return {
19     output: {
20       filename: "js/server.js",
21       publicPath: "/",
22       hashFunction: "xxhash64",
23     },
24     resolve: {
25       extensions: [".js", ".jsx", ".ts", ".tsx"],
26       alias: {
27         "@": path.resolve(__dirname, "src/"),
28         "@utils": path.resolve(__dirname, "src/shared/utils/"),
29       },
30     },
31     performance: {
32       hints: false,
33     },
34     module: {
35       rules: [
36         {
37           test: /\.(scss|css)$/i,
38           use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
39         },
40         {
41           test: /\.(js|jsx|tsx|ts)$/, // All ts and tsx files will be process by
42           exclude: /node_modules/, // ignore node_modules
43           loader: "babel-loader",
44         },
45         // Due to some weird babel issue: https://github.com/webpack/webpack/issues/11467
46         {
47           test: /\.m?js/,
48           resolve: {
49             fullySpecified: false,
50           },
51         },
52       ],
53     },
54     plugins: [
55       new webpack.DefinePlugin({
56         "process.env.COMMIT_HASH": `"${env.COMMIT_HASH}"`,
57         "process.env.NODE_ENV": `"${mode}"`,
58       }),
59       new MiniCssExtractPlugin({
60         filename: "styles/styles.css",
61       }),
62       new CopyPlugin({
63         patterns: [{ from: "./src/assets", to: "./assets" }],
64       }),
65       new webpack.BannerPlugin({
66         banner,
67       }),
68     ],
69   };
70 }
71
72 const createServerConfig = (env, mode) => {
73   const base = getBase(env, mode);
74   const config = merge({}, base, {
75     mode,
76     entry: "./src/server/index.tsx",
77     output: {
78       filename: "js/server.js",
79     },
80     target: "node",
81     externals: [nodeExternals(), "inferno-helmet"],
82   });
83
84   if (mode === "development") {
85     // config.cache = {
86     //   type: "filesystem",
87     //   name: "server",
88     // };
89
90     config.plugins.push(
91       new RunNodeWebpackPlugin({
92         runOnlyInWatchMode: true,
93       })
94     );
95   }
96
97   return config;
98 };
99
100 const createClientConfig = (env, mode) => {
101   const base = getBase(env, mode);
102   const config = merge({}, base, {
103     mode,
104     entry: "./src/client/index.tsx",
105     output: {
106       filename: "js/client.js",
107       publicPath: `/static/${env.COMMIT_HASH}/`,
108     },
109     plugins: [
110       ...base.plugins,
111       new ServiceWorkerPlugin({
112         enableInDevelopment: mode !== "development", // this may seem counterintuitive, but it is correct
113         workbox: {
114           cacheId: "lemmy",
115           include: [/(assets|styles|js)\/.+\..+$/g],
116           inlineWorkboxRuntime: true,
117           runtimeCaching: [
118             {
119               urlPattern: ({
120                 sameOrigin,
121                 url: { pathname, host },
122                 request: { method },
123               }) =>
124                 (sameOrigin || host.includes("localhost")) &&
125                 (!(
126                   pathname.includes("pictrs") || pathname.includes("static")
127                 ) ||
128                   method === "POST"),
129               handler: "NetworkFirst",
130               options: {
131                 cacheName: "instance-cache",
132               },
133             },
134             {
135               urlPattern: ({ url: { pathname, host }, sameOrigin }) =>
136                 (sameOrigin || host.includes("localhost")) &&
137                 pathname.includes("static"),
138               handler: mode === "development" ? "NetworkFirst" : "CacheFirst",
139               options: {
140                 cacheName: "static-cache",
141                 expiration: {
142                   maxAgeSeconds: 60 * 60 * 24,
143                 },
144               },
145             },
146             {
147               urlPattern: ({ url: { pathname }, request: { method } }) =>
148                 pathname.includes("pictrs") && method === "GET",
149               handler: "StaleWhileRevalidate",
150               options: {
151                 cacheName: "image-cache",
152                 expiration: {
153                   maxAgeSeconds: 60 * 60 * 24,
154                 },
155               },
156             },
157           ],
158         },
159       }),
160     ],
161   });
162
163   if (mode === "none") {
164     const BundleAnalyzerPlugin =
165       require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
166     config.plugins.push(new BundleAnalyzerPlugin());
167   }
168
169   return config;
170 };
171
172 module.exports = (env, properties) => [
173   createServerConfig(env, properties.mode || "development"),
174   createClientConfig(env, properties.mode || "development"),
175 ];