123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- const path = require('path')
- const { resolveEntry, fileToComponentName } = require('./resolveWcEntry')
- module.exports = (api, { target, entry, name, 'inline-vue': inlineVue }) => {
- // Disable CSS extraction and turn on CSS shadow mode for vue-style-loader
- process.env.VUE_CLI_CSS_SHADOW_MODE = true
- const { log, error } = require('@vue/cli-shared-utils')
- const abort = msg => {
- log()
- error(msg)
- process.exit(1)
- }
- const cwd = api.getCwd()
- const webpack = require('webpack')
- const vueMajor = require('../../util/getVueMajor')(cwd)
- if (vueMajor === 3) {
- abort(`Vue 3 support of the web component target is still under development.`)
- }
- const isAsync = /async/.test(target)
- // generate dynamic entry based on glob files
- const resolvedFiles = require('globby').sync(entry.split(','), { cwd: api.resolve('.') })
- if (!resolvedFiles.length) {
- abort(`entry pattern "${entry}" did not match any files.`)
- }
- let libName
- let prefix
- if (resolvedFiles.length === 1) {
- // in single mode, determine the lib name from filename
- libName = name || fileToComponentName('', resolvedFiles[0]).kebabName
- prefix = ''
- if (libName.indexOf('-') < 0) {
- abort(`--name must contain a hyphen when building a single web component.`)
- }
- } else {
- // multi mode
- libName = prefix = (name || api.service.pkg.name)
- if (!libName) {
- abort(`--name is required when building multiple web components.`)
- }
- }
- const dynamicEntry = resolveEntry(prefix, libName, resolvedFiles, isAsync)
- function genConfig (minify, genHTML) {
- const config = api.resolveChainableWebpackConfig()
- // make sure not to transpile wc-wrapper
- config.module
- .rule('js')
- .exclude
- .add(/vue-wc-wrapper/)
- // only minify min entry
- if (!minify) {
- config.optimization.minimize(false)
- }
- config
- .plugin('webpack-virtual-modules')
- .use(require('webpack-virtual-modules'), [{
- [dynamicEntry.filePath]: dynamicEntry.content
- }])
- config
- .plugin('web-component-options')
- .use(webpack.DefinePlugin, [{
- 'process.env.CUSTOM_ELEMENT_NAME': JSON.stringify(libName)
- }])
- // enable shadow mode in vue-loader
- config.module
- .rule('vue')
- .use('vue-loader')
- .tap(options => {
- options.shadowMode = true
- return options
- })
- if (genHTML) {
- config
- .plugin('demo-html')
- .use(require('html-webpack-plugin'), [{
- template: path.resolve(__dirname, `./demo-wc.html`),
- inject: false,
- filename: 'demo.html',
- libName,
- vueMajor,
- components:
- prefix === ''
- ? [libName]
- : resolvedFiles.map(file => {
- return fileToComponentName(prefix, file).kebabName
- })
- }])
- }
- // set entry/output last so it takes higher priority than user
- // configureWebpack hooks
- // set proxy entry for *.vue files
- config.resolve
- .alias
- .set('~root', api.resolve('.'))
- const rawConfig = api.resolveWebpackConfig(config)
- // externalize Vue in case user imports it
- rawConfig.externals = [
- ...(Array.isArray(rawConfig.externals) ? rawConfig.externals : [rawConfig.externals]),
- { ...(inlineVue || { vue: 'Vue' }) }
- ].filter(Boolean)
- const entryName = `${libName}${minify ? `.min` : ``}`
- rawConfig.entry = {
- [entryName]: dynamicEntry.filePath
- }
- Object.assign(rawConfig.output, {
- filename: `${entryName}.js`,
- chunkFilename: `${libName}.[name]${minify ? `.min` : ``}.js`,
- // use dynamic publicPath so this can be deployed anywhere
- // the actual path will be determined at runtime by checking
- // document.currentScript.src.
- publicPath: ''
- })
- // to ensure that multiple copies of async wc bundles can co-exist
- // on the same page.
- rawConfig.output.uniqueName = `vue-lib-${libName}`
- return rawConfig
- }
- return [
- genConfig(false, true),
- genConfig(true, false)
- ]
- }
|