0

I am writing a custom webpack loader to remove unnecessary code that Terser can't pick up.

Here's the sample source output from webpack loader;

const SvgsMap = {
  map1: () => {
    return '1';
  },
  map2: () => {
    return '2';
  },
  map3: () => {
    return '3';
  },
  // ...redacted
  map100: () => {
    return '100';
  },
}

Note that above comes into the loader as a string. And I have a whitelist of string[] as which of them that should be included in the build output;

const whitelistsArr = ["map1"]

I am currently writing a webpack loader to pre-process this before getting into bundled. Which currently uses Node VM that I assume could parse it to javascript object, in which then I can remove some of the unused properties in SvgsMap, then output it back again as a string.

My question is;

  1. Am I doing it the right way with Loader to remove them? Or is it actually a webpack plugin job to do this? Any other alternatives?
  2. I am hitting a rock doing this with VM, It seems like it's unable to mutate the existing code and output it back as a string. Am I wrong here?

Any suggestion is appreciated.


Here's my loader's code so far;

const path = require( 'path' );
const { loader } = require( 'webpack' );
const vm = require( 'vm' );

const whitelists = ['frame21Web'];

const loaderFn = function ( source ) {
  /** @type {loader.LoaderContext} */
  // eslint-disable-next-line babel/no-invalid-this
  const self = this;
  const filename = path.basename( self.resourcePath );
  const templateWithoutLoaders = filename.replace( /^.+!/, '' ).replace( /\?.+$/, '' );
  const vmContext = vm.createContext( { module: {} } );
  let newSource = '';
  try {
    const vmScript = new vm.Script( source, { filename: templateWithoutLoaders } );
    const cachedData = vmScript.createCachedData();
    console.log(cachedData.toString()); // Doesn't seem to output as a string.

  }
  catch (err) {
    console.error(err);
  }
  console.log( 'loader', filename, source );
  process.exit( 0 );
  return source;
};

module.exports = loaderFn;

1 Answer 1

2

There may be a couple answers to this question. Difficult to know without knowing the reasoning behind the removal.

If you have control of the file, you could use a combination of Webpack's Define plugin, and some if/else logic. For example

// in your WP config file

  new webpack.DefinePlugin({
    IS_CLIENT: JSON.stringify(true), // will only be true when compiled via WP
  });
// in your module

  if (process.env.IS_CLIENT) {
    SvgsMap.map1 = () => '1';
  }

The above pattern allows for adding/removing chunks of code for your Client bundle, while also allowing for use on the Server.

The other option would be to write a custom Babel plugin (not a WP plugin). I found this article helpful in the past, when I had to write some plugins. Babel gives you more control of how the parts of a JS file are processed, and you can use that plugin outside of WP (like while running Unit tests).

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

Comments

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.