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