Skip to content

Instantly share code, notes, and snippets.

@krisanalfa
Created July 28, 2021 12:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krisanalfa/e17ce5cb2b633e6a706811d7ecef8a0f to your computer and use it in GitHub Desktop.
Save krisanalfa/e17ce5cb2b633e6a706811d7ecef8a0f to your computer and use it in GitHub Desktop.
Simple Webpack Plugin
import { rollup } from 'rollup'
import { babel } from '@rollup/plugin-babel'
import nodeResolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import { terser } from 'rollup-plugin-terser'
import replace from '@rollup/plugin-replace'
import { Compiler, compilation } from 'webpack'
import { Tapable } from 'tapable'
export class RollupPlugin implements Tapable.Plugin {
constructor(
private readonly options: {
/**
* Input of the file you want to transpile.
*/
input: string
/**
* The destination of transpiled file (relative to webpack output path).
*/
destination: string
/**
* The returning object must be:
* ```ts
* interface Replacer {
* [keyInProcessEnv: string]: string
* }
* ```
*
* This object will be used to replace strings in our bundle
* (utilised by `@rollup/plugin-replace` plugin).
* The value of the object is the default value when the
* value of `process.env[keyInProcessEnv]` is falsy. For example:
* ```ts
* // Input
* {
* NODE_ENV: 'production'
* }
*
* // Output
* {
* 'process.env.NODE_ENV': process.env.NODE_ENV || 'production'
* }
* ```
*
* The first param of the function is the instance of `NodeJS.ProcessEnv`,
* you can utilize this param if you want to get the value from other env.
* For example:
* ```ts
* // Input
* {
* replacer: (env) => ({
* NODE_ENV: env.CI ? 'production' : 'development'
* })
* }
*
* // Output
* {
* NODE_ENV: process.env.NODE_ENV
* || (process.env.CI ? 'production' : 'development')
* }
* ```
*
*/
replacer: (env: NodeJS.ProcessEnv) => Record<string, string>
}
) {}
public apply(compiler: Compiler) {
const { input, destination } = this.options
compiler.hooks.emit.tapPromise(
RollupPlugin.name,
async (compilation: compilation.Compilation) => {
try {
const bundle = await rollup({
input,
plugins: [
nodeResolve(),
replace({
...this.normalizeReplacer(),
preventAssignment: true,
}),
commonjs(),
babel({
babelHelpers: 'bundled',
babelrc: false,
configFile: false,
exclude: ['node_modules/**'],
presets: [['@babel/preset-env']],
}),
terser(),
],
})
const {
output: [{ code }],
} = await bundle.generate({
format: 'es',
})
compilation.assets[destination] = {
source: () => code,
size: () => code.length,
}
} catch (error) {
compilation.errors.push(error)
}
}
)
}
private normalizeReplacer() {
const replacer = this.options.replacer(process.env)
return Object.keys(replacer).reduce(
(a, c) => ({
...a,
[`process.env.${c}`]: JSON.stringify(process.env[c] || replacer[c]),
}),
<Record<string, string>>{}
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment