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