6

I'm reducing my js bundle size and stumbled upon core-js. It takes around 62kB which represents ~24% of the whole package.

enter image description here

I tried using @babel/preset-env, but wasn't able to shrink the size any further. Not sure if I'm using the "right" settings:

'@babel/preset-env',
  {
    targets: {
      browsers: ['>1%'],
    },
    useBuiltIns: 'usage',
    corejs: { version: 3, proposals: true },
  },

The full webpack.config.js

const path = require('path');
const webpack = require('webpack');
const dotenv = require('dotenv');
const copyWebpackPlugin = require('copy-webpack-plugin');
const bundleOutputDir = './dist';

/* eslint-disable import/no-extraneous-dependencies */
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

// const CompressionPlugin = require('compression-webpack-plugin');

module.exports = (env) => {
  // get project ID (environment)
  const projectID = process.env.PROJECT_ID;
  if (!projectID || projectID === undefined) {
    throw new Error('Need env variable PROJECT_ID');
  }

  const isDevEnvironment = !(projectID === 'production-project');
  const isDevBuild = !(env && env.prod);
  const analyzeBundle = env && env.analyze;

  // call dotenv and it will return an Object with a parsed key
  const dotEnv = isDevEnvironment ? dotenv.config({ path: './.env.development' }).parsed : dotenv.config().parsed;

  // reduce it to a nice object, the same as before
  const envKeys = Object.keys(dotEnv).reduce((prev, next) => {
    const updatedPrev = prev;
    updatedPrev[`process.env.${next}`] = JSON.stringify(dotEnv[next]);
    return updatedPrev;
  }, {});

  envKeys['process.env.PROJECT_ID'] = JSON.stringify(projectID);

  // need to remove quotes from env
  const publicURL = 'https:/mysite.com'

  const plugins = [new webpack.DefinePlugin(envKeys), new ForkTsCheckerWebpackPlugin()];
  if (isDevBuild) {
    // eslint-disable-next-line new-cap
    plugins.push(new webpack.SourceMapDevToolPlugin(), new copyWebpackPlugin([{ from: 'dev/' }]));
  } else {
    // Don't need to enable compressinon plugin as Firebase Hosting automatically zips the files for us
    // plugins.push(new CompressionPlugin());
  }

  if (analyzeBundle) {
    // eslint-disable-next-line global-require
    const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
    plugins.push(new BundleAnalyzerPlugin());
  }

  const babelPlugins = [
    // syntax sugar found in React components
    '@babel/proposal-class-properties',
    '@babel/proposal-object-rest-spread',
    // transpile JSX/TSX to JS
    [
      '@babel/plugin-transform-react-jsx',
      {
        // we use Preact, which has `Preact.h` instead of `React.createElement`
        pragma: 'h',
        pragmaFrag: 'Fragment',
      },
    ],
    [
      'transform-react-remove-prop-types',
      {
        removeImport: !isDevBuild,
      },
    ],
  ];

  if (!isDevBuild) {
    babelPlugins.push(['transform-remove-console', { exclude: ['error', 'warn'] }]);
  }

  return [
    {
      entry: './src/index.ts',
      output: {
        filename: 'widget.js',
        path: path.resolve(bundleOutputDir),
        publicPath: isDevBuild ? '' : publicURL,
      },
      devServer: {
        host: '0.0.0.0', // your ip address
        port: 8080,
        disableHostCheck: true,
        contentBase: bundleOutputDir,
        open: 'google chrome',
      },
      plugins,
      optimization: {
        minimize: !isDevBuild,
        nodeEnv: 'production',
        mangleWasmImports: true,
        removeAvailableModules: true,
        usedExports: true,
        sideEffects: true,
        providedExports: true,
        concatenateModules: true,
      },
      mode: isDevBuild ? 'development' : 'production',
      module: {
        rules: [
          // packs PNG's discovered in url() into bundle
          {
            test: /\.(jpe?g|png|webp)$/i,
            use: [
              {
                loader: 'responsive-loader',
                options: {
                  // eslint-disable-next-line global-require
                  adapter: require('responsive-loader/sharp'),
                  // sizes: [160, 320, 640, 960, 1280],
                  name: '[path][name]-[width].[ext]',
                  sourceMap: isDevBuild,
                },
              },
            ],
          },
          { test: /\.svg/, use: ['@svgr/webpack'] },
          {
            test: /\.(css)$/i,
            use: [
              {
                loader: 'style-loader',
                options: {
                  injectType: 'singletonStyleTag',
                },
              },
              {
                // allows import CSS as modules
                loader: 'css-loader',
                options: {
                  modules: {
                    // css class names format
                    localIdentName: '[name]-[local]-[hash:base64:5]',
                  },
                  sourceMap: isDevBuild,
                },
              },
            ],
          },
          {
            test: /\.(scss)$/i,
            use: [
              {
                loader: 'style-loader',
                options: { injectType: 'singletonStyleTag' },
              },
              {
                // allows import CSS as modules
                loader: 'css-loader',
                options: {
                  modules: {
                    // css class names format
                    localIdentName: '[name]-[local]-[hash:base64:5]',
                  },
                  sourceMap: isDevBuild,
                },
              },
              {
                loader: 'sass-loader',
                options: {
                  sourceMap: isDevBuild,
                },
              },
            ],
          },
          // use babel-loader for TS and JS modeles,
          // starting v7 Babel babel-loader can transpile TS into JS,
          // so no need for ts-loader
          // note, that in dev we still use tsc for type checking
          {
            test: /\.(js|ts|tsx|jsx)$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'babel-loader',
                options: {
                  presets: [
                    [
                      '@babel/preset-env',
                      {
                        targets: {
                          browsers: ['>1%'],
                        },
                        useBuiltIns: 'usage',
                        corejs: { version: 3, proposals: true },
                      },
                    ],
                    [
                      // enable transpiling ts => js
                      '@babel/typescript',
                      // tell babel to compile JSX using into Preact
                      { jsxPragma: 'h' },
                    ],
                  ],
                  plugins: babelPlugins,
                },
              },
            ],
          },
        ],
      },
      resolve: {
        extensions: ['*', '.js', '.ts', '.tsx'],
        plugins: [new TsconfigPathsPlugin()],
        alias: {
          react: 'preact/compat',
          'react-dom': 'preact/compat',
          images: path.join(__dirname, 'images'),
          sharedimages: path.resolve(__dirname, '../../packages/shared/src/resources'),
        },
      },
    },
  ];
};

2
  • Same issue here, with useBuiltIns: "usage", last 3 versions, not dead query and it takes 62kb gzipped, did you find the reason ? Commented Jul 15, 2021 at 10:40
  • Unfortunately, I haven't found a way to reduce the size yet. Commented Jul 15, 2021 at 14:16

1 Answer 1

0

It looks like the targets property for @babel/preset-env is no longer used and instead the browserlist is recommended to include the list of supported browsers. https://babeljs.io/docs/en/babel-preset-env#browserslist-integration

Sign up to request clarification or add additional context in comments.

1 Comment

While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.