async client(internalBuildConfig = {}) {
        let {globals, build, serviceWorker} = this.config;

        /* eslint-disable fecs-one-var-per-line */
        let {publicPath, filenames, cssSourceMap, cssMinimize, cssExtract,
            jsSourceMap, bundleAnalyzerReport, extend, extendWithWebpackChain,
            babel,
            defines: {client: clientDefines = {}},
            alias: {client: clientAlias = {}},
            plugins: {base: basePlugins = [], client: clientPlugins = []}} = Object.assign({}, build, internalBuildConfig);
        /* eslint-enable fecs-one-var-per-line */

        let clientConfig = await this.base(Object.assign(internalBuildConfig, {
            babelOptions: this.generateBabelOptions(babel, true)
        }));

        // set output format
        clientConfig.output
            .filename(assetsPath(filenames.entry))
            .chunkFilename(assetsPath(filenames.chunk));

        // add alias for client
        Object.keys(clientAlias).forEach(aliasKey => {
            clientConfig.resolve.alias.set(aliasKey, clientAlias[aliasKey]);
        });

        // add module.rules for style
        this.addStyleRules(clientConfig, {
            cssSourceMap,
            cssMinimize,
            cssExtract
        });

        // set sourcemap in dev & prod mode
        clientConfig.devtool(jsSourceMap ? (this.isDev ? 'cheap-module-eval-source-map' : 'nosources-source-map') : false);

        // modify vars in DefinePlugin
        clientConfig.plugin('define').init((Plugin, args) =>
            new Plugin(Object.assign(args[0], {
                'process.env.VUE_ENV': '"client"',
                'process.env.NODE_ENV': `"${this.env}"`
            }, clientDefines)));

        // split vendor js into its own file
        clientConfig.plugin('chunk-vendor').use(webpack.optimize.CommonsChunkPlugin, [{
            name: 'vendor',
            filename: assetsPath(filenames.vendor),
            minChunks(module, count) {
                // any required modules inside node_modules are extracted to vendor
                return module.resource
                    && /\.js$/.test(module.resource)
                    && module.resource.indexOf('node_modules') >= 0;
            }
        }]);

        // split vue, vue-router, vue-meta and vuex into vue chunk
        clientConfig.plugin('chunk-vue').use(webpack.optimize.CommonsChunkPlugin, [{
            name: 'vue',
            filename: assetsPath(filenames.vue),
            minChunks(module, count) {
                // On Windows, resource path will be seperated by '\',
                // then paths like '\node_modules\vue\' cannot be matched because of '\v'.
                // Transforming into '::node_modules::vue::' can solve this.
                const PATH_SEP = '::';
                let resource = module.resource;
                let replacedResource = resource ? resource.split(sep).join(PATH_SEP) : '';
                let targets = ['vue', 'vue-router', 'vuex', 'vue-meta'];
                // /^(::vue::|::vue-router::)$/i
                let npmRegExp = new RegExp(PATH_SEP + targets.join('::|::') + PATH_SEP, 'i');
                // /^(_vue@2.4.2@vue|_vue-router@1.2.3@vue-router)$/i
                let cnpmRegExp
                    = new RegExp(targets.map(t => `_${t}@\\d+\\.\\d+\\.\\d+@${t}`).join('|'), 'i');

                return resource
                    && replacedResource.indexOf('node_modules') !== -1
                    && (npmRegExp.test(replacedResource) || cnpmRegExp.test(replacedResource));
            }
        }]);

        // extract webpack runtime and module manifest to its own file in order to
        // prevent vendor hash from being updated whenever app bundle is updated
        clientConfig.plugin('chunk-manifest').use(webpack.optimize.CommonsChunkPlugin, [{
            name: 'manifest',
            chunks: ['vue']
        }]);

        // Copy static files to /dist.
        let copyList = [{
            from: join(globals.rootDir, ASSETS_DIRNAME_IN_DIST),
            to: ASSETS_DIRNAME_IN_DIST,
            ignore: ['*.md']
        }];
        clientConfig.plugin('copy').use(CopyWebpackPlugin, [copyList]);

        if (this.isProd && serviceWorker && serviceWorker.enable !== false) {
            // Use workbox@3.x in prod mode.
            useWorkbox(clientConfig, this.config);

            // After useWorkbox, serviceWorker.enable maybe changed
            if (serviceWorker.enable !== false) {
                // inject register code for service worker into HTML
                clientConfig.plugin('sw-register').use(SWRegisterWebpackPlugin, [{
                    filePath: resolve(__dirname, 'templates/sw-register.js'),
                    prefix: (serviceWorker && serviceWorker.swPath) || publicPath
                }]).after('html');
            }
        }

        // Bundle analyzer.
        if (bundleAnalyzerReport) {
            clientConfig.plugin('bundle-analyzer').use(BundleAnalyzerPlugin, [bundleAnalyzerReport]);
        }

        // call extendWithWebpackChain function if provided
        let extendWithWebpackChainArray = [
            extendWithWebpackChain,
            this.config.build.extendWithWebpackChain
        ];
        for (let i = 0; i < extendWithWebpackChainArray.length; i++) {
            let extendFunc = extendWithWebpackChainArray[i];
            if (typeof extendFunc === 'function') {
                await extendFunc(clientConfig, {
                    type: 'client',
                    env: this.env
                });
            }
        }

        // convert webpackChain to plain webpack config object
        let webpackConfigObject = clientConfig.toConfig();

        if (basePlugins && basePlugins.length) {
            webpackConfigObject.plugins = [...webpackConfigObject.plugins, ...basePlugins];
        }
        if (clientPlugins && clientPlugins.length) {
            webpackConfigObject.plugins = [...webpackConfigObject.plugins, ...clientPlugins];
        }

        // call extend function if provided
        if (typeof extend === 'function') {
            extend.call(this, webpackConfigObject, {
                type: 'base',
                env: this.env
            });
            extend.call(this, webpackConfigObject, {
                type: 'client',
                env: this.env
            });
        }

        return webpackConfigObject;
    }
generate client base config based on lavas config

@param {Object} internalBuildConfig build config
@return {Object} client base config