Edit documentation Edit document
SSR/SSG

Bundling

Content

HTML, CSS and Assets

Html, scss and assets files that are in the project folder are copiyng using a "CopyWebpackPlugin" plugin. Also, bundle process is mutating html files by adding scripts with special attribute "data-server-only" that indicated about data that needs to be processed in SSR and removed for CSR.

This part of webpack config is written in ./webpack.common.js

plugins: [
        new CopyWebpackPlugin({
            patterns: [

                /* COPYING ALL IMAGES */
                {
                    from: 'assets/images',
                    to: 'assets/images',
                    context: 'src/',
                    noErrorOnMissing: true
                },

                /* COPYING CSS FILES */
                {
                    from: 'assets/css/**/*.css',
                    to: '[path][name].css',
                    context: 'src/'
                },
                /* COPYING ALL HTML FILES */
                {
                    from: '**/*.html',
                    to: '[path][name].html',
                    context: 'src/',
                    filter: (resourcePath) => {
                        return !resourcePath.includes('/assets/');
                    },
                    transform: (content, resourcePath) => {
                        return new Promise(resolve => {
                            let string = content.toString();
                            let data = string.split('<body>');
                            let modified = data[0] + '<body><script data-server-only src="https://unpkg.com/@gudhub/core@1.2.0/umd/library.min.js"></script><script data-server-only src="https://unpkg.com/@gudhub/gh-component/dist/main.js"></script>' + data[1];

                            data = modified.split('<head>');
                            modified = data[0] + '<head><script id="base_write_script">document.write(`<base href="${window.MODE === \'production\' ? \'https\' : \'http\'}://${window.getConfig().website}">`);document.querySelector("#base_write_script").remove();</script>' + data[1];

                            data = modified.split('</body>');
                            modified = data[0] + '<script data-server-only src="/assets/js/bundle.js"></script></body>' + data[1];
                            resolve(Buffer.from(modified, 'utf-8'));

                        });
                    }
                },

                /* COPYING ROBOTS.TXT */
                {
                    from: 'robots.txt',
                    to: 'robots.txt',
                    context: 'src/'
                },

                /* COPYING FAVICON */
                {
                    from: 'favicon.ico',
                    to: 'favicon.ico',
                    context: 'src'
                }
            ]
        }),
        new MiniCssExtractPlugin({
            filename: '[name].css'
        }),
        new GenerateJsonFromJsPlugin({
            path: 'config.mjs',
            filename: 'config.json'
        })
    ]

Also we have handwritten plugin "GenerateJsonFromJsPlugin", his response is to convert "./config.mjs" to JSON file.

You can modify this file if you need additional files to bundle.

Components bundling

Components can be bundled in 2 ways:

  • all in one : all components are combined into a single bundle.js and bundle.css file. This bundle is need for puppeteer work;

    Code responsible for that located in ./webpack.bundle.js:

    export default {
        /* BUNDLING WEBCOMPONENTS */
        entry: () => {
            const entries = glob.sync('./src/assets/js/components/**/*.js');
    
            // adds "node_modules/@gudhub/ssg-web-components-library" entries
            const gudhubEntries = (() => {
                const entries = [];
                for (const componentConfig of GudhubComponents) {
                    entries.push('./node_modules/' + componentConfig.src);
                }
                return entries;
            })()
    
            return [
                ...entries,
                ...gudhubEntries
            ];
        },
        output: {
            path: path.resolve('dist/assets/js'),
            filename: "bundle.js"
        },
        module: {
            rules: [
                {
                    test: /\.html$/i,
                    loader: 'html-loader',
                    options: {
                        minimize: false,
                        sources: false
                    }
                },
                {
                    test: /\.(s(a|c)ss)$/,
                    use: [
                        {
                            loader: MiniCssExtractPlugin.loader
                        },
                        {
                            loader: 'css-loader',
                            options: {
                                url: false
                            }
                        },
                        'sass-loader'
                    ]
                }
            ]
        },
        plugins: [
            new MiniCssExtractPlugin({
                filename: 'bundle.css'
            })
        ]
    }
    
  • separately: each component collects js and css files into a separate folder named as a component. This need for puppeteer to make bundle with components for page;

    Code responsible for that located in ./webpack.common.js:

    export default {
        ...
    
        /* BUNDLING WEBCOMPONENTS */
        entry: () => {
            const entries = glob.sync('./src/assets/js/**/*.js').reduce((obj, el) => {
                obj[el.replace('src/', '')] = el;
                return obj;
            }, {});
    
            // adds entries from @gudhub/ssg-web-components-library
            const gudhubEntries = (() => {
                const entries = [];
                for (const componentConfig of GudhubComponents) {
                    entries.push('./node_modules/' + componentConfig.src);
                }
    
                return entries.reduce((obj, el) => {
                    const path = el;
                    const componentsIndex = path.indexOf('/components');
                    obj[path.replace(path.substring(0, componentsIndex), '/assets/js/')] = el;
                    return obj;
                }, {});
            })()
    
    
            return {
                ...entries,
                ...gudhubEntries
            };
        },
        output: {
            path: path.resolve('dist'),
            filename: "[name]",
        },
        module: {
            rules: [
                {
                    test: /\.html$/i,
                    loader: 'html-loader',
                    options: {
                        minimize: false,
                        sources: false
                    }
                },
                {
                    test: /\.(s(a|c)ss)$/,
                    use: [
                        {
                            loader: MiniCssExtractPlugin.loader
                        },
                        {
                            loader: 'css-loader',
                            options: {
                                url: false
                            }
                        },
                        'sass-loader'
                    ],
                }
            ]
        }
    }