resolveWcConfig.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. const path = require('path')
  2. const { resolveEntry, fileToComponentName } = require('./resolveWcEntry')
  3. module.exports = (api, { target, entry, name, 'inline-vue': inlineVue }) => {
  4. // Disable CSS extraction and turn on CSS shadow mode for vue-style-loader
  5. process.env.VUE_CLI_CSS_SHADOW_MODE = true
  6. const { log, error } = require('@vue/cli-shared-utils')
  7. const abort = msg => {
  8. log()
  9. error(msg)
  10. process.exit(1)
  11. }
  12. const cwd = api.getCwd()
  13. const vueMajor = require('../../util/getVueMajor')(cwd)
  14. if (vueMajor === 3) {
  15. abort(`Vue 3 support of the web component target is still under development.`)
  16. }
  17. const isAsync = /async/.test(target)
  18. // generate dynamic entry based on glob files
  19. const resolvedFiles = require('globby').sync(entry.split(','), { cwd: api.resolve('.') })
  20. if (!resolvedFiles.length) {
  21. abort(`entry pattern "${entry}" did not match any files.`)
  22. }
  23. let libName
  24. let prefix
  25. if (resolvedFiles.length === 1) {
  26. // in single mode, determine the lib name from filename
  27. libName = name || fileToComponentName('', resolvedFiles[0]).kebabName
  28. prefix = ''
  29. if (libName.indexOf('-') < 0) {
  30. abort(`--name must contain a hyphen when building a single web component.`)
  31. }
  32. } else {
  33. // multi mode
  34. libName = prefix = (name || api.service.pkg.name)
  35. if (!libName) {
  36. abort(`--name is required when building multiple web components.`)
  37. }
  38. }
  39. const dynamicEntry = resolveEntry(prefix, libName, resolvedFiles, isAsync)
  40. function genConfig (minify, genHTML) {
  41. const config = api.resolveChainableWebpackConfig()
  42. // make sure not to transpile wc-wrapper
  43. config.module
  44. .rule('js')
  45. .exclude
  46. .add(/vue-wc-wrapper/)
  47. // only minify min entry
  48. if (!minify) {
  49. config.optimization.minimize(false)
  50. }
  51. config
  52. .plugin('web-component-options')
  53. .use(require('webpack').DefinePlugin, [{
  54. 'process.env.CUSTOM_ELEMENT_NAME': JSON.stringify(libName)
  55. }])
  56. // enable shadow mode in vue-loader
  57. config.module
  58. .rule('vue')
  59. .use('vue-loader')
  60. .tap(options => {
  61. options.shadowMode = true
  62. return options
  63. })
  64. if (genHTML) {
  65. config
  66. .plugin('demo-html')
  67. .use(require('html-webpack-plugin'), [{
  68. template: path.resolve(__dirname, `./demo-wc.html`),
  69. inject: false,
  70. filename: 'demo.html',
  71. libName,
  72. vueMajor,
  73. components:
  74. prefix === ''
  75. ? [libName]
  76. : resolvedFiles.map(file => {
  77. return fileToComponentName(prefix, file).kebabName
  78. })
  79. }])
  80. }
  81. // set entry/output last so it takes higher priority than user
  82. // configureWebpack hooks
  83. // set proxy entry for *.vue files
  84. config.resolve
  85. .alias
  86. .set('~root', api.resolve('.'))
  87. const rawConfig = api.resolveWebpackConfig(config)
  88. // externalize Vue in case user imports it
  89. rawConfig.externals = [
  90. ...(Array.isArray(rawConfig.externals) ? rawConfig.externals : [rawConfig.externals]),
  91. { ...(inlineVue || { vue: 'Vue' }) }
  92. ].filter(Boolean)
  93. const entryName = `${libName}${minify ? `.min` : ``}`
  94. rawConfig.entry = {
  95. [entryName]: dynamicEntry
  96. }
  97. Object.assign(rawConfig.output, {
  98. // to ensure that multiple copies of async wc bundles can co-exist
  99. // on the same page.
  100. jsonpFunction: libName.replace(/-\w/g, c => c.charAt(1).toUpperCase()) + '_jsonp',
  101. filename: `${entryName}.js`,
  102. chunkFilename: `${libName}.[name]${minify ? `.min` : ``}.js`,
  103. // use dynamic publicPath so this can be deployed anywhere
  104. // the actual path will be determined at runtime by checking
  105. // document.currentScript.src.
  106. publicPath: ''
  107. })
  108. return rawConfig
  109. }
  110. return [
  111. genConfig(false, true),
  112. genConfig(true, false)
  113. ]
  114. }