async addHtmlPlugin(spaConfig, baseUrl = '/') {
        // allow user to provide a custom HTML template
        let {globals: {rootDir}, skeleton: {enable: enableSkeleton, asyncCSS}, build: {cssExtract}} = this.config;
        let htmlFilename;
        let templatePath;
        let tempTemplatePath;

        htmlFilename = `${DEFAULT_ENTRY_NAME}.html`;

        // find core/spa.html.tmpl
        templatePath = join(rootDir, `core/${SPA_TEMPLATE_HTML}`);
        if (!pathExistsSync(templatePath)) {
            // find core/index.html.tmpl
            templatePath = join(rootDir, `core/${TEMPLATE_HTML}`);
        }

        if (!pathExistsSync(templatePath)) {
            throw new Error(`${SPA_TEMPLATE_HTML} or ${TEMPLATE_HTML} required`);
        }

        tempTemplatePath = basename(templatePath);

        // write HTML template used by html-webpack-plugin which doesn't support template STRING
        let resolvedTemplatePath = await this.writeFileToLavasDir(
            tempTemplatePath,
            templateUtil.client(await readFile(templatePath, 'utf8'), baseUrl)
        );

        /**
         * don't inject <link rel=stylesheet> in head,
         * use <link rel=preload> to load CSS asynchronously instead
         * https://github.com/lavas-project/lavas/issues/73
         */
        let entryClientContent = await readFile(join(rootDir, 'core/entry-client.js'), 'utf8');
        let shouldUpdateLavasTemplate = entryClientContent.indexOf('window.mountLavas') === -1;
        let enableAsyncCSS = asyncCSS && enableSkeleton && cssExtract;
        this.config.enableAsyncCSS = enableAsyncCSS && !shouldUpdateLavasTemplate;
        if (enableAsyncCSS) {
            if (shouldUpdateLavasTemplate) {
                Logger.warn('build', 'If you want to render Skeleton faster, please update `entry-client.js`. You can refer to https://github.com/lavas-project/lavas/issues/73.');
            }
            else {
                spaConfig.plugin('ommit-css').use(OmmitCSSPlugin);
            }
        }

        // add html webpack plugin
        spaConfig.plugin('html').use(HtmlWebpackPlugin, [{
            filename: htmlFilename,
            template: resolvedTemplatePath,
            inject: true,
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeAttributeQuotes: true
            },
            favicon: assetsPath('img/icons/favicon.ico'),
            chunksSortMode: 'dependency',
            cache: false,
            chunks: ['manifest', 'vue', 'vendor', DEFAULT_ENTRY_NAME],
            config: this.config // use config in template
        }]);

        return {resolvedTemplatePath, tempTemplatePath};
    }
use html webpack plugin

@param {Object} spaConfig spaConfig
@param {string} baseUrl baseUrl from config/router
@return {string} resolvedTemplatePath html template's path