]> Untitled Git - lemmy-ui.git/blob - webpack.config.js
9afdb5266f3b75e7cb5b3aad66981c96f9eceb73
[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) {
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       }),
58       new MiniCssExtractPlugin({
59         filename: "styles/styles.css",
60       }),
61       new CopyPlugin({
62         patterns: [{ from: "./src/assets", to: "./assets" }],
63       }),
64       new webpack.BannerPlugin({
65         banner,
66       }),
67     ],
68   };
69 }
70
71 const createServerConfig = (env, mode) => {
72   const base = getBase(env);
73   const config = merge({}, base, {
74     mode,
75     entry: "./src/server/index.tsx",
76     output: {
77       filename: "js/server.js",
78     },
79     target: "node",
80     externals: [nodeExternals(), "inferno-helmet"],
81   });
82
83   if (mode === "development") {
84     // config.cache = {
85     //   type: "filesystem",
86     //   name: "server",
87     // };
88
89     config.plugins.push(
90       new RunNodeWebpackPlugin({
91         runOnlyInWatchMode: true,
92       })
93     );
94   }
95
96   return config;
97 };
98
99 const createClientConfig = (env, mode) => {
100   const base = getBase(env);
101   const config = merge({}, base, {
102     mode,
103     entry: "./src/client/index.tsx",
104     output: {
105       filename: "js/client.js",
106       publicPath: `/static/${env.COMMIT_HASH}/`,
107     },
108     plugins: [
109       ...base.plugins,
110       new ServiceWorkerPlugin({
111         enableInDevelopment: mode !== "development", // this may seem counterintuitive, but it is correct
112         workbox: {
113           modifyURLPrefix: {
114             "/": `/static/${env.COMMIT_HASH}/`,
115           },
116           cacheId: "lemmy",
117           include: [/(assets|styles|js)\/.+\..+$/g],
118           inlineWorkboxRuntime: true,
119           runtimeCaching: [
120             {
121               urlPattern: ({
122                 sameOrigin,
123                 url: { pathname, host },
124                 request: { method },
125               }) =>
126                 (sameOrigin || host.includes("localhost")) &&
127                 (!(
128                   pathname.includes("pictrs") || pathname.includes("static")
129                 ) ||
130                   method === "POST"),
131               handler: "NetworkFirst",
132               options: {
133                 cacheName: "instance-cache",
134               },
135             },
136             {
137               urlPattern: ({ url: { pathname, host }, sameOrigin }) =>
138                 (sameOrigin || host.includes("localhost")) &&
139                 pathname.includes("static"),
140               handler: mode === "development" ? "NetworkFirst" : "CacheFirst",
141               options: {
142                 cacheName: "static-cache",
143                 expiration: {
144                   maxAgeSeconds: 60 * 60 * 24,
145                 },
146               },
147             },
148             {
149               urlPattern: ({ url: { pathname }, request: { method } }) =>
150                 pathname.includes("pictrs") && method === "GET",
151               handler: "StaleWhileRevalidate",
152               options: {
153                 cacheName: "image-cache",
154                 expiration: {
155                   maxAgeSeconds: 60 * 60 * 24,
156                 },
157               },
158             },
159           ],
160         },
161       }),
162     ],
163   });
164
165   if (mode === "none") {
166     const BundleAnalyzerPlugin =
167       require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
168     config.plugins.push(new BundleAnalyzerPlugin());
169   }
170
171   return config;
172 };
173
174 module.exports = (env, properties) => [
175   createServerConfig(env, properties.mode || "development"),
176   createClientConfig(env, properties.mode || "development"),
177 ];