You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
4.1 KiB
143 lines
4.1 KiB
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) |
|
] |
|
}
|
|
|