liusuyi
2023-04-24 4737f1e038743ced243c9e52423404d9034d6107
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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 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,
            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)
  ]
}