]> Untitled Git - lemmy-ui.git/blob - webpack.config.js
Enforce SameSite=Strict (#1713)
[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           modifyURLPrefix: {
115             "/": `/static/${env.COMMIT_HASH}/`,
116           },
117           cacheId: "lemmy",
118           include: [/(assets|styles|js)\/.+\..+$/g],
119           inlineWorkboxRuntime: true,
120           runtimeCaching: [
121             {
122               urlPattern: ({
123                 sameOrigin,
124                 url: { pathname, host },
125                 request: { method },
126               }) =>
127                 (sameOrigin || host.includes("localhost")) &&
128                 (!(
129                   pathname.includes("pictrs") || pathname.includes("static")
130                 ) ||
131                   method === "POST"),
132               handler: "NetworkFirst",
133               options: {
134                 cacheName: "instance-cache",
135               },
136             },
137             {
138               urlPattern: ({ url: { pathname, host }, sameOrigin }) =>
139                 (sameOrigin || host.includes("localhost")) &&
140                 pathname.includes("static"),
141               handler: mode === "development" ? "NetworkFirst" : "CacheFirst",
142               options: {
143                 cacheName: "static-cache",
144                 expiration: {
145                   maxAgeSeconds: 60 * 60 * 24,
146                 },
147               },
148             },
149             {
150               urlPattern: ({ url: { pathname }, request: { method } }) =>
151                 pathname.includes("pictrs") && method === "GET",
152               handler: "StaleWhileRevalidate",
153               options: {
154                 cacheName: "image-cache",
155                 expiration: {
156                   maxAgeSeconds: 60 * 60 * 24,
157                 },
158               },
159             },
160           ],
161         },
162       }),
163     ],
164   });
165
166   if (mode === "none") {
167     const BundleAnalyzerPlugin =
168       require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
169     config.plugins.push(new BundleAnalyzerPlugin());
170   }
171
172   return config;
173 };
174
175 module.exports = (env, properties) => [
176   createServerConfig(env, properties.mode || "development"),
177   createClientConfig(env, properties.mode || "development"),
178 ];