DEV Community

loading...
Cover image for Setting Up a JavaScript Build Process using Rollup

Setting Up a JavaScript Build Process using Rollup

plebras profile image Pierre Le Bras ・14 min read

Notes:

  • The following instructions were inspired and updated from this blog post;
  • Since these instructions where written, some package might have been deprecated or moved, make sure to check their status, on their website or GitHub/npm pages;
  • This setup will use Node.js and npm (node package manager). Follow this link for installation instructions.

Content:

  1. Goals
  2. Getting Started
  3. Rollup
  4. Babel
  5. ESLint
  6. Third-Party and Non-ES Modules Support
  7. Enabling the ENV Variable
  8. Terser
  9. Less and PostCSS
  10. Automating Builds
  11. Building Multiple Modules
  12. Final Notes

Goals

The goal of this setup is to allow the development and build of multiple JavaScript front-end modules and associated stylesheets using Rollup.
The idea is to have a src folder where scripts and styles can be developed. These sources would then be processed and bundled together in an app folder, ready to be used in the browser:

-- project/
   |-- app/
   |   |-- dist/
   |   |   | // build modules (scripts and styles) go here
   |   |-- [main.js]
   |   |-- [main.css]
   |   |-- index.html
   |-- src/
   |   |-- scripts/
   |   |   | // JavaScript source code goes here
   |   |-- styles/
   |   |   | // Less stylesheet sources go here
Enter fullscreen mode Exit fullscreen mode

While setting up this process, we will explore many aspects of the modern JavaScript ecosystem: bundling, transpiling, linting, and minifying.

Getting Started

First, we are going to create a project directory, add the above project structure, and enter the project directory:

mkdir -p project/{app/dist, src/{scripts,styles}} 
touch project/app/index.html
cd project 
Enter fullscreen mode Exit fullscreen mode

We can then initialise a node project by typing the next command and following the instructions:

npm init
Enter fullscreen mode Exit fullscreen mode

It will create a package.json file for us, which describes the scope and dependencies of the project.

Rollup

Rollup.js is a module bundler for JavaScript: it gets pieces of code that are dependent on each other to create a larger, self-contained module. It uses the standardized module format introduced in ES6. Rollup also uses a tree-shaking approach to bundling, removing unused pieces of code which could bulk your module unnecessarily.

To add it to the project, we type in the following command:

npm install --save-dev rollup
Enter fullscreen mode Exit fullscreen mode

--save-dev is an option that tells npm we want this library to be saved as a project dependency, in particular for development purposes (as opposed to dependencies for the code itself). If you check the package.json file, you will see the following added:

// package.json
"devDependencies": {
    "rollup": "^2.36.1"
}
Enter fullscreen mode Exit fullscreen mode

Although the version number might be different.

Next, we are going to create a configuration file for Rollup, rollup.config.js:

// rollup.config.js
export default {
  input: 'src/scripts/foo.js',
  output: {
    file: 'app/dist/foo.js',
    format: 'iife',
    name: 'Foo',
    sourcemap: 'inline'
  }
}
Enter fullscreen mode Exit fullscreen mode
  • input is the file we want Rollup to process and bundle sources from;
  • output contains the options for our built module:
    • file is where we want the bundle saved;
    • format lets us choose one of the many JavaScript flavor our bundle will have, check the options list there. Here we choose iife which will wrap the module in a self-executed function (immediately-invoked function expression), making the module declare itself in its own scope to avoid clashing with other scripts;
    • name is the name we want to use when referring to the module in the front-end app, e.g. const bar = Foo.bar();, note that it is only useful if the script we build has an export statement;
    • sourcemap lets us describe how we want the module sourcemap to be generated, a sourcemap is extremely useful when debugging code. Here chose inline to have it contained in the generated bundled module file.

Testing the Configuration

Let's give a quick test to Rollup and our configuration. Inside src/scripts we will create a directory utils and add an operations.js file in it:

mkdir src/scripts/utils
touch src/scripts/utils/operations.js
Enter fullscreen mode Exit fullscreen mode

operations.js will contain two functions, sum and prod, both returning the sum and the product of two arguments respectively. These two functions are exported by the operations module:

// src/scripts/operations.js
const sum = (a,b)=>{ return a+b; }
const prod = (a,b)=>{ return a*b; }
export {sum, prod};
Enter fullscreen mode Exit fullscreen mode

Inside src/scripts we will create the module foo.js:

touch src/scripts/foo.js
Enter fullscreen mode Exit fullscreen mode

Which will load the functions from operations.js and log the result of a sum on two variables:

// src/scripts/foo.js
import {sum, prod} from './utils/operations.js';
const A = 4;
const B = 5;
export default function(){
    console.log(sum(A,B));
}
Enter fullscreen mode Exit fullscreen mode

We can then run Rollup on src/scripts/foo.js, note the option -c which tells Rollup to use the configuration file we have made earlier:

./node_modules/.bin/rollup -c
Enter fullscreen mode Exit fullscreen mode

And then check the resulting module in app/dist/foo.js:

// app/dist/foo.js
var Foo = (function () {
    'use strict';

    const sum = (a,b)=>{
        return a+b;
    };

    const A = 4;
    const B = 5;

    function foo () {
      console.log(sum(A, B));
    }

    return foo;

}());
//# sourceMappingURL= ...
Enter fullscreen mode Exit fullscreen mode

Right then we can note a few things:

  • the content of operations.js and foo.js have been bundled together;
  • only the function sum was extracted from operations, that the tree-shaking from Rollup: because foo.js does not use prod, there is no need to bundle it;
  • the sourcemap has been added to the file

Babel

Babel is a JavaScript transpiler, taking code following modern JavaScript standards and producing the corresponding code in earlier versions of JavaScript with more browser support. We are first going to add two packages from Babel:

 npm install --save-dev @babel/core @babel/preset-env
Enter fullscreen mode Exit fullscreen mode

And then one Rollup plugin to integrate Babel:

 npm install --save-dev @rollup/plugin-babel
Enter fullscreen mode Exit fullscreen mode

Next, we can create the configuration file for Babel, .babelrc, telling it which preset to use when transpiling:

// .babelrc
{
    "presets": [
        ["@babel/preset-env", {
            "modules": false
        }]
    ]
}
Enter fullscreen mode Exit fullscreen mode

The env preset is a smart preset that uses Browserlist under the hood to determine which syntax is best to transpile to.
The final step is to let Rollup know that it should call babel during the bundling process. To do so we are going to update the Rollup configuration file:

// rollup.config.js
import babel from '@rollup/plugin-babel';

export default {
    input: 'src/scripts/foo.js',
    output: { ... },
    plugins: [
        babel({
            exclude:'node_modules/**',
            babelHelpers: 'bundled'
        })
    ]
}
Enter fullscreen mode Exit fullscreen mode

After importing the babel plugin, we call it in the plugins list and instruct it to ignore the code from dependencies
Now, when running Rollup:

./node_modules/.bin/rollup -c
Enter fullscreen mode Exit fullscreen mode

We get the following result in app/dist/foo.js:

// app/dist/foo.js
var Foo = (function () {
    'use strict';

    var sum = function sum(a, b) {
      return a + b;
    };

    var A = 8;
    var B = 9;

    function foo () {
      console.log(sum(A, B));
    }

    return foo;

}());
//# sourceMappingURL=
Enter fullscreen mode Exit fullscreen mode

Because we used the defaults browserslist configuration, the sum function has been changed from an arrow definition to a normal function statement, and const has been replaced with var.

If we were to enter "browserslist": ["last 2 Chrome versions"] in our package.json (meaning we are targeting an environment limited to the last 2 versions of Chrome), there would not be any changes to the bundle, given that the last versions of Chrome are fully compatible with ES6 features.

ESLint

ESLint is a linter, a program that will analyse our code to correct syntax and detect problems (missing brackets/parentheses, unused variables, etc.) during the build process. We are first going to add it to our project:

npm install --save-dev eslint
Enter fullscreen mode Exit fullscreen mode

As well as a Rollup plugin for it:

npm install --save-dev @rollup/plugin-eslint
Enter fullscreen mode Exit fullscreen mode

Next, we need to configure ESLint, using the .eslintrc.json file, which can be done by using the following command:

./node_modules/.bin/eslint --init
Enter fullscreen mode Exit fullscreen mode

ESLint will then prompt a series of questions to initialise the configuration file:

? How would you like to use ESLint?
  > To check syntax and find problems
? What type of modules does your project use?
  > JavaScript modules (import/export)
? Which framework does your project use?
  > None of these
? Does your project use TypeScript?
  > No
? Where does your code run?
  > Browser
? What format do you want your config file to be in?
  > JSON
Enter fullscreen mode Exit fullscreen mode

Our project should then include a new .eslintrc.json file, with this content:

// .eslintrc.json
{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "rules": {
    }
}
Enter fullscreen mode Exit fullscreen mode

We can then add more the list of rules, for example, having indents set to 4 spaces, using Unix linebreaks, using single quotes, enforcing semicolons at the end of each statement, and warning us of unused variables:

// .eslintrc.json
{ ...
    "rules":{
        "indent": ["warn", 4],
        "linebreak-style": ["warn", "unix"],
        "quotes": ["warn", "single"],
        "semi": ["warn", "always"],
        "no-unused-vars": ["warn"]
    }
}
Enter fullscreen mode Exit fullscreen mode

Next, we can update rollup.config.js to include ESLint in the process:

// rollup.config.js
import babel from '@rollup/plugin-babel';
import eslint from '@rollup/plugin-eslint';

export default {
    input: 'src/scripts/foo.js',
    output: { ... },
    plugins: [
        eslint({
            fix: true,
            exclude: ['./node_modules/**', './src/styles/**'],
        }),
        babel({ ... })
    ]
}
Enter fullscreen mode Exit fullscreen mode

As with Babel, we have first imported it, before including it in the list of plugins. We have instructed it to ignore our styles files, and let fix some of the simpler issues silently (e.g. semicolons, indentation, etc.).
Now, when we run:

./node_modules/.bin/rollup -c
Enter fullscreen mode Exit fullscreen mode

We can notice the following terminal output, informing us that foo.js defines (or imports) prod but does not use it.

/.../project/src/scripts/foo.js
  1:14  warning  'prod' is defined but never used  no-unused-vars

✖ 1 problem (0 errors, 1 warning)
Enter fullscreen mode Exit fullscreen mode

And ESLint has fixed some of the trivial syntax issues for us:

// src/scripts/operations.js before build
const sum = (a,b)=>{
    return a+b;
};
const prod = (a,b)=>{
return a*b
}

export {sum, prod};

// src/scripts/operations.js after build
const sum = (a,b)=>{
    return a+b;
};
const prod = (a,b)=>{
    return a*b;
};

export {sum, prod};
Enter fullscreen mode Exit fullscreen mode

Third-Party and Non-ES Modules Support

By default, Rollup does not load third party libraries from node_modules properly. To enable that we need to use another Rollup plugin, node-resolve:

npm install --save-dev @rollup/plugin-node-resolve
Enter fullscreen mode Exit fullscreen mode

Then, while we are developing ES modules, some of our code dependencies in node_modules would have been developed in a non-ES module format: CommonJS. Trying to load these in our bundle will ultimately fail, but Rollup has a plugin to help with that, commonjs:

npm install --save-dev @rollup/plugin-commonjs
Enter fullscreen mode Exit fullscreen mode

Once we have added those plugins to the project, we can add them the Rollup configuration:

// rollup.config.js
import babel from '@rollup/plugin-babel';
import eslint from '@rollup/plugin-eslint';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

export default {
    input: 'src/scripts/foo.js',
    output: { ... },
    plugins: [
        resolve(),
        commonjs(),
        eslint({ ... }),
        babel({ ... })
    ]
}
Enter fullscreen mode Exit fullscreen mode

Enabling the ENV Variable

Using environment variables can be helpful in the development process, for example turning logging on and off depending on the type of build we are doing, for development or production.
Let's add the following to src/scripts/foo.js:

// src/scripts/foo.js
...
if(ENV != 'production'){
    console.log('not in production');
}
...
Enter fullscreen mode Exit fullscreen mode

A piece of code that logs a message when the build is not for production. However, the variable ENV is undefined there. To fix that we can add the Rollup plugin replace:

npm install --save-dev @rollup/plugin-replace
Enter fullscreen mode Exit fullscreen mode

And use it in the configuration file:

// rollup.config.js
import babel from '@rollup/plugin-babel';
import eslint from '@rollup/plugin-eslint';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';

export default {
    input: 'src/scripts/foo.js',
    output: { ... },
    plugins: [
        resolve(),
        commonjs(),
        eslint({ ... }),
        babel({ ... }),
        replace({
            exclude: 'node_modules/**',
            ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
        })
    ]
}
Enter fullscreen mode Exit fullscreen mode

What it will do is replace, in our bundle (excluding code that comes from third-party libraries in node_modules), the occurrences of ENV with the value of NODE_ENV or development by default. What we must remember is to update .eslintrc.json to let ESLint know that ENV is a global variable and not undeclared:

// .eslintrc.json
{
    "env": { ... },
    "globals": {
        "ENV": true
    },
    "extends": "eslint:recommended",
    "parserOptions": { ... },
    "rules": { ... }
}
Enter fullscreen mode Exit fullscreen mode

Then when building normally:

./node_modules/.bin/rollup -c
Enter fullscreen mode Exit fullscreen mode

app/dist/foo.js will include the following:

// app/dist/foo.js
...
{
    console.log('not in production');
}
...
Enter fullscreen mode Exit fullscreen mode

However, building for production:

NODE_ENV=production ./node_modules/.bin/rollup -c
Enter fullscreen mode Exit fullscreen mode

Will remove the code above from app/dist/foo.js.

Terser

Generating a bundle that has many dependencies, from our code or third-party packages, will result in a large JavaScript file. To optimize the bundle it is useful to integrate Terser into our build process. What Terser does is it removes comments, shorten variables names, cut whitespaces and minify our code to make it the shortest possible.
Again Terser can be integrated with Rollup using a plugin:

npm install --save-dev rollup-plugin-terser
Enter fullscreen mode Exit fullscreen mode

And configure it in rollup.config.js:

// rollup.config.js
import babel from '@rollup/plugin-babel';
import eslint from '@rollup/plugin-eslint';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
import {terser} from 'rollup-plugin-terser';

export default {
    input: 'src/scripts/foo.js',
    output: {
        file: 'app/dist/foo.js',
        format: 'iife',
        name: 'Foo',
        sourcemap: (process.env.NODE_ENV === 'production' ? false : 'inline')
    },
    plugins: [
        resolve(),
        commonjs(),
        eslint({ ... }),
        babel({ ... }),
        replace({ ... }),
        (process.env.NODE_ENV === 'production' && terser())
    ]
}
Enter fullscreen mode Exit fullscreen mode

Because it is useful to be able to inspect and see our code during development, we are only letting terser execute if NODE_ENV is set to production. Similarly, we have turned off the sourcemap in production to reduce the bundle size.
If we now build our module for production:

NODE_ENV=production ./node_modules/.bin/rollup -c
Enter fullscreen mode Exit fullscreen mode

Here is how it looks:

// app/dist/foo.js
var Foo=function(){"use strict";return function(){console.log(8+9)}}();
Enter fullscreen mode Exit fullscreen mode

Less and PostCSS

Now that we have addressed our scripts, we can focus on our styles. In this setup, we will look at the CSS preprocessor Less which lets us write CSS simpler, use variables and mixins. We can add it to the project with the following command:

npm install --save-dev less
Enter fullscreen mode Exit fullscreen mode

To process Less files we will use PostCSS, which is a JavaScript build tool for CSS, Less, and other CSS preprocessors. It also comes with a built-in minifier. We can add it to the project with a Rollup plugin:

npm install --save-dev rollup-plugin-postcss
Enter fullscreen mode Exit fullscreen mode

One of the most interesting features of PostCSS is Autoprefixer. Much like Babel, it checks our browserslist requirement to add prefixes to CSS rules, ensuring cross-browser compatibilities. We can add it to the project with the following command:

npm install --save-dev autoprefixer
Enter fullscreen mode Exit fullscreen mode

We can now set this up with Rollup, in the configuration file:

// rollup.config.js
import babel from '@rollup/plugin-babel';
import eslint from '@rollup/plugin-eslint';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
import {terser} from 'rollup-plugin-terser';
import postcss from 'rollup-plugin-postcss';
import autoprefixer from 'autoprefixer';

export default {
    input: 'src/scripts/foo.js',
    output: { ... },
    plugins: [
        resolve(),
        commonjs(),
        eslint({ ... }),
        babel({ ... }),
        replace({ ... }),
        (process.env.NODE_ENV === 'production' && terser()),
        postcss({
            plugins: [autoprefixer()],
            inject: false,
            extract: true,
            sourceMap: (process.env.NODE_ENV === 'production' ? false : 'inline'),
            minimize: (process.env.NODE_ENV === 'production')
        })
    ]
}
Enter fullscreen mode Exit fullscreen mode

As we can see, PostCSS calls Autoprefixer as a plugin, it uses Less in the background automatically when detecting Less files. The inject option lets us define whether the JavaScript module will inject styles in the <head> of our page (true) or not (false). Similarly, the extract option lets us define whether a separate stylesheet will be generated next to the JavaScript module (true) or not (false). This stylesheet will have the same filename as the JavaScript module, with a .css extension instead. Then, we set the sourcemap and minimize options depending on NODE_ENV as we did with the JavaScript module.
Processing a stylesheet can then be done by simply importing it in our JavaScript module:

/* src/styles/foo.less */
@clr: red;
h1{
  color: @clr;
}
Enter fullscreen mode Exit fullscreen mode
// src/scripts/foo.js
import '../styles/foo.less';
...
Enter fullscreen mode Exit fullscreen mode
NODE_ENV=production ./node_modules/.bin/rollup -c
Enter fullscreen mode Exit fullscreen mode
/* app/dist/foo.css */
h1{color:red}
Enter fullscreen mode Exit fullscreen mode

Automating Builds

The next step of this setup is to make use of node scripts to automate the build process.
First, we are going to install reload, an HTTP server program that comes with a live-reload functionality:

npm install --save-dev reload
Enter fullscreen mode Exit fullscreen mode

Reload can then serve app/ to localhost and reload anytime it detects a change.
Meanwhile, Rollup comes with a watch option, -w, that keeps it listening to any changes in our source file to automatically re-build them. We can therefore combine the two in one Node script in our package.json:

// package.json
...
"scripts": {
    "serve": "./node_modules/.bin/reload -b -d ./app -p 8000 | ./node_modules/.bin/rollup -c -w"
}
...
Enter fullscreen mode Exit fullscreen mode

Then, running:

npm run server
Enter fullscreen mode Exit fullscreen mode

Will launch both Reload and Rollup: Rollup listening to any changes on the source file and re-building them, and Reload detecting changes in the build files and re-serving them on our test webpage localhost:8000.
We can then add a second script for production build:

// package.json
...
"scripts": {
    "serve": "./node_modules/.bin/reload -b -d ./app -p 8000 | ./node_modules/.bin/rollup -c -w",
    "build": "NODE_ENV=production ./node_modules/.bin/rollup -c"
}
...
Enter fullscreen mode Exit fullscreen mode

Then, we can run the following to simply build our production application:

npm run build
Enter fullscreen mode Exit fullscreen mode

Building Multiple Modules

Finally, we can setup rollup.config.js to allow multiple modules to be bundled separatley:

// rollup.config.js
import babel from '@rollup/plugin-babel';
import eslint from '@rollup/plugin-eslint';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
import {terser} from 'rollup-plugin-terser';
import postcss from 'rollup-plugin-postcss';
import autoprefixer from 'autoprefixer';

const srcDir = 'src/scripts/',
    distDir = 'app/dist/';

const plugins = () => [
    resolve(),
    commonjs(),
    eslint({ ... }),
    babel({ ... }),
    replace({ ... }),
    (process.env.NODE_ENV === 'production' && terser()),
    postcss({ ... })
];

function setupBuild(src, dist, name){
    return {
        input: srcDir+src,
        output: {
            file: distDir+dist,
            format: 'iife',
            name,
            sourcemap: (process.env.NODE_ENV === 'production' ? false : 'inline')
        },
        plugins:plugins()
    }
}

export default [
    setupBuild('foo.js', 'foo.js', 'Foo'),
    setupBuild('bar.js', 'bar.js', 'Bar')
]
Enter fullscreen mode Exit fullscreen mode

Additional modules can be added using setupBuild. Note that we use a function to return plugins to "clean" their buffers.

Final Notes

Using Builds

The built modules can be simply loaded into an HTML page:

<!-- app.index.html -->
<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="dist/foo.css">
        <script src="dist/foo.js"></script>
    </head>
    <body>
        <h1>Hello World</h1>
        <script>
            Foo();
        </script>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

As any other JavaScript code, it will get executed upon loading. If the module exports a value (object or function), it can be accessed using the name given in the Rollup configuration (third parameter of setupBuild). For example: Foo(), Foo[...] or Foo.bar.

Managing Warnings

Some third-party libraries like d3.js will have circular dependencies within them, which Rollup will warn us about when building the module. To avoid getting many warning messages, we can add a warning filter to in the Rollup configuration:

// rollup.config.js
...
function setupBuild(src, dist, name){
    return {
        input: srcDir+src,
        output: { ... },
        plugins:plugins(),
        onwarn: function(warning, warner){
            // if circular dependency warning
            if (warning.code === 'CIRCULAR_DEPENDENCY'){
                // if comming from a third-party
                if(warning.importer && warning.importer.startsWith('node_modules/')){
                    // ignore warning
                    return;
                }
            }
            // Use default for everything else
            warner(warning);
        }
    }
}
...
Enter fullscreen mode Exit fullscreen mode

Final Project Structure

This how the project directory should look like now:

-- project/
   |-- app/
   |   |-- dist/
   |   |   |-- foo.js
   |   |   |-- foo.css
   |   |-- index.html
   |-- src/
   |   |-- scripts/
   |   |   |-- utils/
   |   |   |   |-- operations.js
   |   |   |-- foo.js
   |   |-- styles/
   |   |   |-- foo.less
   |-- .babelrc
   |-- .eslintrc.json
   |-- package-lock.json
   |-- package.json
   |-- rollup.config.js
Enter fullscreen mode Exit fullscreen mode

The package.json file should contain the following:

// package.json
{
  ...
  "scripts": {
    "serve": "./node_modules/.bin/reload -b -d ./app -p 8000 | ./node_modules/.bin/rollup -c -w",
    "build": "NODE_ENV=production ./node_modules/.bin/rollup -c"
  },
  ...
  "devDependencies": {
    "@babel/core": "^7.12.10",
    "@babel/preset-env": "^7.12.11",
    "@rollup/plugin-babel": "^5.2.2",
    "@rollup/plugin-commonjs": "^17.0.0",
    "@rollup/plugin-eslint": "^8.0.1",
    "@rollup/plugin-node-resolve": "^11.1.0",
    "@rollup/plugin-replace": "^2.3.4",
    "autoprefixer": "^10.2.1",
    "eslint": "^7.17.0",
    "less": "^4.1.0",
    "reload": "^3.1.1",
    "rollup": "^2.36.1",
    "rollup-plugin-postcss": "^4.0.0",
    "rollup-plugin-terser": "^7.0.2"
  },
  "browserslist": [
    "defaults"
  ]
  ...
}
Enter fullscreen mode Exit fullscreen mode

.babelrc should look like this:

// .babelrc
{
    "presets": [
        ["@babel/preset-env", {
            "modules": false
        }]
    ]
}
Enter fullscreen mode Exit fullscreen mode

.eslintrc.json should look like this:

// .eslintrc.json
{
    "env": {
        "browser": true,
        "es2021": true
    },
    "globals": {
        "ENV": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "rules": {
        "indent": ["warn", 4],
        "linebreak-style": ["warn", "unix"],
        "quotes": ["warn", "single"],
        "semi": ["warn", "always"],
        "no-unused-vars": ["warn"]
    }
}
Enter fullscreen mode Exit fullscreen mode

And finally, rollup.config.js should have the following:

// rollup.config.js
import babel from '@rollup/plugin-babel';
import eslint from '@rollup/plugin-eslint';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
import {terser} from 'rollup-plugin-terser';
import postcss from 'rollup-plugin-postcss';
import autoprefixer from 'autoprefixer';

const srcDir = 'src/scripts/',
    distDir = 'app/dist/';

const plugins = () => [
    resolve(),
    commonjs(),
    eslint({
        fix: true,
        exclude: ['./node_modules/**', './src/styles/**']
    }),
    babel({
        exclude: 'node_modules/**',
        babelHelpers: 'bundled'
    }),
    replace({
        exclude: 'node_modules/**',
        ENV: JSON.stringify(process.env.NODE_ENV || 'development')
    }),
    (process.env.NODE_ENV === 'production' && terser()),
    postcss({
        plugins: [autoprefixer()],
        inject: false,
        extract: true,
        sourceMap: (process.env.NODE_ENV === 'production' ? false : 'inline'),
        minimize: (process.env.NODE_ENV === 'production')
    })
]

function setupBuild(src, dist, name){
    return {
        input: srcDir+src,
        output: {
            file: distDir+dist,
            format: 'iife',
            name,
            sourcemap: (process.env.NODE_ENV === 'production' ? false : 'inline')
        },
        plugins:plugins(),
        onwarn: function(warning, warner){
            if (warning.code === 'CIRCULAR_DEPENDENCY'){
                if(warning.importer && warning.importer.startsWith('node_modules/')){
                    return;
                }
            }
            warner(warning);
        }
    }
}

export default[
    setupBuild('foo.js', 'foo.js', 'Foo')
]
Enter fullscreen mode Exit fullscreen mode

Discussion (0)

pic
Editor guide