Skip to content

A starter Webpack boilerplate for generating single page applications (SPAs).

License

Notifications You must be signed in to change notification settings

chuntington/webpack-boilerplate

Repository files navigation

Webpack Boilerplate

GitHub GitHub package.json version GitHub code size GitHub last commit

A starter Webpack boilerplate for generating single page applications (SPAs). Node.js v18+ is required. This project utilizes dot-env and cross-env to store and communicate any information prescribed to the build environment.

For the beekeepers:

For the script kidz:

  • SWC (Transpiling and compiling)
  • Terser (Uglifying and compressing)
  • ESLint (Keeping things in order)
  • [Insert testing framework here]

To get started, clone the project and install the dependencies:

> git clone https://github.com/chuntington/webpack-boilerplate.git
> cd webpack-boilerplate/
> npm install

Create a .env file in the root directory and specify the build environment inside:

NODE_ENV=development
// or
NODE_ENV=production

In the terminal, build the project once, or build on save:

> npm run build
> npm run watch

If you need a local web server, the following will start one and build on save:

> npm run serve

The generated bundle will be placed inside the /dist directory.

If you need to update the Google Fonts source list, provide a valid API key to the following script:

> npm run google-fonts --apikey=YOUR_API_KEY

Installing a framework

Note: When using styled components, the extracted CSS is likely to be invalid according to the preset StyleLint rules. You may modify these rules in stylelint.config.js to accommodate, or disable linting completely in postcss.config.js. In addition, it may be helpful to modify or temporarily disable some JavaScript linting rules in eslint.config.js when utilizing any of the below frameworks.

VueJS (3.x)

Below is an example of a Vue.js (3.x) implementation with support for .vue single file components.

In the terminal:

> npm install vue vue-loader vue-eslint-parser

In webpack.config.js, import and assign the appropriate loader, plugins and alias:

const { VueLoaderPlugin } = require('vue-loader');
const Webpack = require('webpack');

module.exports = {
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            // ...
        ]
    },
    plugins: [
        // Set compile-time flags when using the esm-bundler
        new Webpack.DefinePlugin({
            __VUE_OPTIONS_API__: true,
            __VUE_PROD_DEVTOOLS__: DevMode,
            __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: DevMode
        }),
        new VueLoaderPlugin(),
        // ...
    ],
    // Override the alias for template interpolation
    resolve: {
        alias: {
            vue: 'vue/dist/vue.esm-bundler.js'
        }
    }
}

In postcss.config.js, inform Purgecss of any .vue single file components:

Purgecss({
    content: ['./src/**/*.{html,js,vue}'],
    // ...
})

In eslint.config.js, assign the appropriate parser:

module.exports = {
    parser: 'vue-eslint-parser',
    // ...
}

In src/js/components/ExampleComponent.vue, create an example single file component:

<template>
    <h1 class="example">Example Component</h1>
</template>

<script>
    export default {
        data: () => ({
            show: false
        }),
        mounted() {
            this.show = true;
            console.log('Example component mounted.');
        }
    };
</script>

<style>
    .example {
        color: gray;
    }
</style>

In src/index.html, declare an app container with the example component nested inside:

<body class="antialiased">
    <div id="app">
        <example-component></example-component>
    </div>
</body>

In src/js/main.js, import the framework and example component, and initiate a new app instance:

import ExampleComponent from './components/ExampleComponent.vue';
import { createApp } from 'vue';

const vm = createApp({ components: { ExampleComponent } });

vm.mount('#app');

VueJS (2.x)

Below is an example of a Vue.js (2.x) implementation with support for .vue single file components.

In the terminal:

> npm install vue@2 vue-loader@15 vue-template-compiler@2 vue-eslint-parser@8

In webpack.config.js, import and assign the appropriate loader, plugin and alias:

const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            }
            // ...
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
        // ...
    ],
    // Override the alias for template interpolation
    resolve: {
        alias: {
            vue: 'vue/dist/vue.esm.js'
        }
    }
}

In postcss.config.js, inform Purgecss of any .vue single file components:

Purgecss({
    content: ['./src/**/*.{html,js,vue}'],
    // ...
})

In eslint.config.js, assign the appropriate parser:

module.exports = {
    parser: 'vue-eslint-parser',
    // ...
}

In src/js/components/ExampleComponent.vue, create an example single file component:

<template>
    <h1 class="example">Example Component</h1>
</template>

<script>
    export default {
        data: () => ({
            show: false
        }),
        mounted() {
            this.show = true;
            console.log('Example component mounted.');
        }
    };
</script>

<style>
    .example {
        color: gray;
    }
</style>

In src/index.html, declare an app container with the example component nested inside:

<body class="antialiased">
    <div id="app">
        <example-component></example-component>
    </div>
</body>

In src/js/main.js, import the framework and example component, and initiate a new app instance:

import ExampleComponent from './components/ExampleComponent.vue';
import Vue from 'vue';

const vm = new Vue({ components: { ExampleComponent } });

vm.$mount('#app');

SvelteJS (4.x)

Below is an example of a Svelte.js (4.x) implementation with support for .svelte templates.

In the terminal:

> npm install svelte svelte-loader

In webpack.config.js, assign the appropriate loader and resolve configuration:

module.exports = {
    module: {
        rules: [
            {
                test: /\.svelte$/,
                use: {
                    loader: 'svelte-loader',
                    options: {
                        // emitCss: true
                    }
                }
            },
            {
                test: /node_modules\/svelte\/.*\.mjs$/,
                resolve: {
                    fullySpecified: false
                }
            },
            // ...
        ]
    },
    resolve: {
        alias: {
            svelte: Path.resolve('node_modules', 'svelte/src/runtime')
        },
        conditionNames: ['svelte', 'browser', 'import'],
        extensions: ['.mjs', '.js', '.svelte'],
        mainFields: ['svelte', 'browser', 'module', 'main']
    }
}

In postcss.config.js, inform Purgecss of any .svelte templates:

Purgecss({
    content: ['./src/**/*.{html,js,svelte}'],
    // ...
})

In src/js/components/App.svelte, create an example styled component template:

<script>
    import { onMount } from 'svelte';

    export let name;

    onMount(() => {
        console.log(`${name} mounted.`);
    });
</script>

<h1 class="example">{name}</h1>

<style>
    .example {
        color: gray;
    }
</style>

In src/index.html, declare the component container:

<body class="antialiased">
    <div id="app"></div>
</body>

In src/js/main.js, import the component and initiate a new instance:

import App from './components/App.svelte';

const app = new App({
    target: document.getElementById('app'),
    props: { name: 'Example App' }
});

window.app = app;

htmx (1.x)

Below is an example of a htmx (1.x) implementation.

In the terminal:

> npm install htmx.org

In webpack.config.js, assign the appropriate resolve configuration:

module.exports = {
    resolve: {
        alias: {
            htmx: 'htmx.org/dist/htmx.min.js'
        }
    }
}

In src/index.html, declare an app container:

<body hx-on="htmx:load: console.log('Example App mounted.')" class="antialiased">
    <h1>Example App</h1>
</body>

In src/js/main.js, import the framework:

import 'htmx';

ReactJS (18.x)

Below is an example of a React.js (18.x) implementation.

In the terminal:

> npm install eslint-plugin-react react react-dom

In .swcrc, enable the appropriate parser and transform options:

{
    "jsc": {
        "parser": {
            "jsx": true,
            // ...
        },
        "transform": {
            "react": {
                "runtime": "automatic"
            }
        }
    },
    // ...
}

In eslint.config.js, enable the appropriate parser options and plugin:

module.exports = {
    parserOptions: {
        'ecmaFeatures': {
            'jsx': true
        },
        // ...
    },
    plugins: ['react'],
    // ...
}

In src/js/components/ExampleComponent.js, create an example component template:

import React from 'react';

class ExampleComponent extends React.Component {
    render() {
        return <h1>Example Component</h1>;
    }

    componentDidMount() {
        console.log('Example component mounted.');
    }
}

export default ExampleComponent;

In src/index.html, declare an app container:

<body class="antialiased">
    <div id="app"></div>
</body>

In src/js/main.js, import the framework and example component, and initiate a new app instance:

import React from 'react';
import ReactDOM from 'react-dom';
import ExampleComponent from './components/ExampleComponent.js';

class App extends React.Component {
    render() {
        return <ExampleComponent/>;
    }
}

ReactDOM.render(<App/>, document.getElementById('app'));

🎩 Voila!