about summary refs log tree commit diff
path: root/config/webpack
diff options
context:
space:
mode:
Diffstat (limited to 'config/webpack')
-rw-r--r--config/webpack/production.js44
-rw-r--r--config/webpack/shared.js38
2 files changed, 60 insertions, 22 deletions
diff --git a/config/webpack/production.js b/config/webpack/production.js
index cd1dd91dc..e2d7f11dc 100644
--- a/config/webpack/production.js
+++ b/config/webpack/production.js
@@ -9,6 +9,16 @@ const OfflinePlugin = require('offline-plugin');
 const { publicPath } = require('./configuration.js');
 const path = require('path');
 
+let compressionAlgorithm;
+try {
+  const zopfli = require('node-zopfli');
+  compressionAlgorithm = (content, options, fn) => {
+    zopfli.gzip(content, options, fn);
+  };
+} catch (error) {
+  compressionAlgorithm = 'gzip';
+}
+
 module.exports = merge(sharedConfig, {
   output: {
     filename: '[name]-[chunkhash].js',
@@ -33,7 +43,7 @@ module.exports = merge(sharedConfig, {
     }),
     new CompressionPlugin({
       asset: '[path].gz[query]',
-      algorithm: 'gzip',
+      algorithm: compressionAlgorithm,
       test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/,
     }),
     new BundleAnalyzerPlugin({ // generates report.html and stats.json
@@ -48,7 +58,37 @@ module.exports = merge(sharedConfig, {
     }),
     new OfflinePlugin({
       publicPath: publicPath, // sw.js must be served from the root to avoid scope issues
-      caches: { }, // do not cache things, we only use it for push notifications for now
+      caches: {
+        main: [':rest:'],
+        additional: [':externals:'],
+        optional: [
+          '**/locale_*.js', // don't fetch every locale; the user only needs one
+          '**/*_polyfills-*.js', // the user may not need polyfills
+          '**/*.woff2', // the user may have system-fonts enabled
+          // images/audio can be cached on-demand
+          '**/*.png',
+          '**/*.jpg',
+          '**/*.jpeg',
+          '**/*.svg',
+          '**/*.mp3',
+          '**/*.ogg',
+        ],
+      },
+      externals: [
+        '/emoji/1f602.svg', // used for emoji picker dropdown
+        '/emoji/sheet.png', // used in emoji-mart
+      ],
+      excludes: [
+        '**/*.gz',
+        '**/*.map',
+        'stats.json',
+        'report.html',
+        // any browser that supports ServiceWorker will support woff2
+        '**/*.eot',
+        '**/*.ttf',
+        '**/*-webfont-*.svg',
+        '**/*.woff',
+      ],
       ServiceWorker: {
         entry: path.join(__dirname, '../../app/javascript/mastodon/service_worker/entry.js'),
         cacheName: 'mastodon',
diff --git a/config/webpack/shared.js b/config/webpack/shared.js
index e3a1fc379..5d176db4e 100644
--- a/config/webpack/shared.js
+++ b/config/webpack/shared.js
@@ -12,29 +12,27 @@ const localePackPaths = require('./generateLocalePacks');
 const extensionGlob = `**/*{${settings.extensions.join(',')}}*`;
 const entryPath = join(settings.source_path, settings.source_entry_path);
 const packPaths = sync(join(entryPath, extensionGlob));
-const entryPacks = [...packPaths, ...localePackPaths].filter(path => path !== join(entryPath, 'custom.js'));
-
-const themePaths = Object.keys(themes).reduce(
-  (themePaths, name) => {
-    const themeData = themes[name];
-    themePaths[`themes/${name}`] = resolve(themeData.pack_directory, themeData.pack);
-    return themePaths;
-  }, {}
-);
 
 module.exports = {
   entry: Object.assign(
-    entryPacks.reduce(
-      (map, entry) => {
-        const localMap = map;
-        let namespace = relative(join(entryPath), dirname(entry));
-        if (namespace === join('..', '..', '..', 'tmp', 'packs')) {
-          namespace = ''; // generated by generateLocalePacks.js
-        }
-        localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry);
-        return localMap;
+    packPaths.reduce((map, entry) => {
+      const localMap = map;
+      const namespace = relative(join(entryPath), dirname(entry));
+      localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry);
+      return localMap;
+    }, {}),
+    localePackPaths.reduce((map, entry) => {
+      const localMap = map;
+      localMap[basename(entry, extname(entry, extname(entry)))] = resolve(entry);
+      return localMap;
+    }, {}),
+    Object.keys(themes).reduce(
+      (themePaths, name) => {
+        const themeData = themes[name];
+        themePaths[`themes/${name}`] = resolve(themeData.pack_directory, themeData.pack);
+        return themePaths;
       }, {}
-    ), themePaths
+    )
   ),
 
   output: {
@@ -58,7 +56,7 @@ module.exports = {
       }
     ),
     new ExtractTextPlugin({
-      filename: env.NODE_ENV === 'production' ? '[name]-[hash].css' : '[name].css',
+      filename: env.NODE_ENV === 'production' ? '[name]-[contenthash].css' : '[name].css',
       allChunks: true,
     }),
     new ManifestPlugin({