Search code examples
npmterser

Npm scripts - how to minify files from a folder and save them into another?


I'm using npm scripts to compile and minify sass and potentionally javascript files. However, I'm looking for at way to specify a source folder of *.js files and have them minified and saved in a destination folder individually - (flattened, not concatenated) each as *.min.js.

I have tried with npm terser, but it doesn't seem to be able to with with a source folder, only single files, nor does it seem to be able to minify the files individually.

So, what I'm looking for:

Src/
 |__main.js
 |__menu.js
 |__etc...
Dist/
 |__main.min.js
 |__menu.min.js
 |__...

Which npm package should I use for this?


Solution

  • You have two options: terser (javascript) or webpack (TypeScript).

    Terser

    It's better for javascript only.

    How to:

    1. Install
      npm install terser -g
    
      or
    
      yarn add terser
    
    
    1. Create your terser.config.json (in your root folder)
      {
      "compress": true,
      "mangle": true,
      "output": {
        "file": "dist/your-minified-file.js"
      }
    }
    
    1. package.json script:
    {
      (...),
      "scripts": {
        "minify": "terser src/input-file.js -c terser.config.json",
      },
      "devDependencies": {
        "terser": "^5.31.0"
      }
    }
    

    Or, if you want to skip the config file, you need to add the options to your script line. Example: terser src/input-file.js -o dist/minified-file.js.

    More info can be found in the terser page or Terser GitHub

    Webpack

    It is a bit more challenging to configure correctly, but it's better if you use TypeScript:

    1. install
      yarn add -D terser-webpack-plugin webpack webpack-cli webpack-node-externals
    
    
    1. Package.json
    {
      (...),
      "scripts": {
        "minify": "SERVER_ENV=dev webpack --config webpack.config.mjs",
      },
      "devDependencies": {
        "terser-webpack-plugin": "^5.3.10",
        "webpack": "^5.91.0",
        "webpack-cli": "^5.1.4",
        "webpack-node-externals": "^3.0.0"
      }
    }
    

    3) webpack.config.js

    Webpack configuration is more complex and vast. I recommend reading this StackOverflow Answer to better understand the meaning of webpack.DefinePlugin.

    import { resolve, dirname } from 'path';
    import { fileURLToPath } from 'url';
    import nodeExternals from 'webpack-node-externals';
    import NodePolyfillPlugin from 'node-polyfill-webpack-plugin';
    import TerserPlugin from 'terser-webpack-plugin';
    import webpack from 'webpack';
    
    const __filename = fileURLToPath(import.meta.url);
    const __dirname = dirname(__filename);
    const isProd = process.env.SERVER_ENV === 'prod'
    const mode = isProd ? 'production' : 'development';
    
    export default {
      entry: './src/index.ts', // your starting index
      output: {
        path: resolve('dist'),
        filename: 'index.min.js' // your output & folder
      },
      mode,
      module: {
        rules: [
          {
            test: /\.ts$/,
            use: 'ts-loader',
            exclude: /node_modules/
          }
        ]
      },
      target: 'node',
      externals: [nodeExternals()],
      resolve: {
        extensions: ['.ts', '.js'],
        alias: {
          'apis': resolve(__dirname, 'src/apis'), // this allows you to import your scripts using an alias, for example, `import { someApi } from 'apis';`
        }
      },
      optimization: {
        minimize: isProd, // minimization true or false
        minimizer: [new TerserPlugin({
          extractComments: false,
          terserOptions: {
            ecma: 2017,
            output: {
              comments: false
            },
            mangle: {
              toplevel: true
            }
          }
        })]
      },
      plugins: [
        new NodePolyfillPlugin(),
        new webpack.DefinePlugin({
          'process.env': 'process.env', // this is important. You can either pass the env file, a set of properties or 'process.env' to make your script configuration loading more dynamic (check the link below)
        })
      ],
    };
    
    

    Finding this 'process.env': 'process.env', setting was challenging, so I wrote a blog post about it. You can find it here, but I recommend the official documentation (it is not very clear on this topic) to get more info about the webpack possibilities. The official documentation can be found here.