Spaces:
Sleeping
Sleeping
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 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('web-component-options') | |
.use(require('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 | |
} | |
Object.assign(rawConfig.output, { | |
// to ensure that multiple copies of async wc bundles can co-exist | |
// on the same page. | |
jsonpFunction: libName.replace(/-\w/g, c => c.charAt(1).toUpperCase()) + '_jsonp', | |
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: '' | |
}) | |
return rawConfig | |
} | |
return [ | |
genConfig(false, true), | |
genConfig(true, false) | |
] | |
} | |