resolveLibConfig.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. const fs = require('fs')
  2. const path = require('path')
  3. module.exports = (api, { entry, name, formats, filename, 'inline-vue': inlineVue }, options) => {
  4. const { log, error } = require('@vue/cli-shared-utils')
  5. const abort = msg => {
  6. log()
  7. error(msg)
  8. process.exit(1)
  9. }
  10. const vueMajor = require('../../util/getVueMajor')(api.getCwd())
  11. const fullEntryPath = api.resolve(entry)
  12. if (!fs.existsSync(fullEntryPath)) {
  13. abort(
  14. `Failed to resolve lib entry: ${entry}${entry === `src/App.vue` ? ' (default)' : ''}. ` +
  15. `Make sure to specify the correct entry file.`
  16. )
  17. }
  18. const isVueEntry = /\.vue$/.test(entry)
  19. const libName = (
  20. name ||
  21. (
  22. api.service.pkg.name
  23. ? api.service.pkg.name.replace(/^@.+\//, '')
  24. : path.basename(entry).replace(/\.(jsx?|vue)$/, '')
  25. )
  26. )
  27. filename = filename || libName
  28. function genConfig (format, postfix = format, genHTML) {
  29. const config = api.resolveChainableWebpackConfig()
  30. const browserslist = require('browserslist')
  31. const targets = browserslist(undefined, { path: fullEntryPath })
  32. const supportsIE = targets.some(agent => agent.includes('ie'))
  33. const webpack = require('webpack')
  34. config.plugin('need-current-script-polyfill')
  35. .use(webpack.DefinePlugin, [{
  36. 'process.env.NEED_CURRENTSCRIPT_POLYFILL': JSON.stringify(supportsIE)
  37. }])
  38. // adjust css output name so they write to the same file
  39. if (config.plugins.has('extract-css')) {
  40. config
  41. .plugin('extract-css')
  42. .tap(args => {
  43. args[0].filename = `${filename}.css`
  44. return args
  45. })
  46. }
  47. // only minify min entry
  48. if (!/\.min/.test(postfix)) {
  49. config.optimization.minimize(false)
  50. }
  51. // inject demo page for umd
  52. if (genHTML) {
  53. const template = isVueEntry ? 'demo-lib.html' : 'demo-lib-js.html'
  54. config
  55. .plugin('demo-html')
  56. .use(require('html-webpack-plugin'), [{
  57. template: path.resolve(__dirname, template),
  58. inject: false,
  59. filename: 'demo.html',
  60. libName,
  61. vueMajor,
  62. assetsFileName: filename,
  63. cssExtract: config.plugins.has('extract-css')
  64. }])
  65. }
  66. // resolve entry/output
  67. const entryName = `${filename}.${postfix}`
  68. config.resolve
  69. .alias
  70. .set('~entry', fullEntryPath)
  71. // set output target before user configureWebpack hooks are applied
  72. config.output.libraryTarget(format)
  73. // set entry/output after user configureWebpack hooks are applied
  74. const rawConfig = api.resolveWebpackConfig(config)
  75. let realEntry = require.resolve('./entry-lib.js')
  76. // avoid importing default if user entry file does not have default export
  77. if (!isVueEntry) {
  78. const entryContent = fs.readFileSync(fullEntryPath, 'utf-8')
  79. if (!/\b(export\s+default|export\s{[^}]+as\s+default)\b/.test(entryContent)) {
  80. realEntry = require.resolve('./entry-lib-no-default.js')
  81. }
  82. }
  83. // externalize Vue in case user imports it
  84. rawConfig.externals = [
  85. ...(Array.isArray(rawConfig.externals) ? rawConfig.externals : [rawConfig.externals]),
  86. {
  87. ...(inlineVue || {
  88. vue: {
  89. commonjs: 'vue',
  90. commonjs2: 'vue',
  91. root: 'Vue'
  92. }
  93. })
  94. }
  95. ].filter(Boolean)
  96. rawConfig.entry = {
  97. [entryName]: realEntry
  98. }
  99. rawConfig.output = Object.assign({
  100. library: libName,
  101. libraryExport: isVueEntry ? 'default' : undefined,
  102. libraryTarget: format,
  103. // preserve UDM header from webpack 3 until webpack provides either
  104. // libraryTarget: 'esm' or target: 'universal'
  105. // https://github.com/webpack/webpack/issues/6522
  106. // https://github.com/webpack/webpack/issues/6525
  107. globalObject: `(typeof self !== 'undefined' ? self : this)`
  108. }, rawConfig.output, {
  109. filename: `${entryName}.js`,
  110. chunkFilename: `${entryName}.[name].js`,
  111. // use dynamic publicPath so this can be deployed anywhere
  112. // the actual path will be determined at runtime by checking
  113. // document.currentScript.src.
  114. publicPath: ''
  115. })
  116. if (format === 'commonjs2') {
  117. // #6188
  118. delete rawConfig.output.library
  119. }
  120. return rawConfig
  121. }
  122. const configMap = {
  123. commonjs: genConfig('commonjs2', 'common'),
  124. umd: genConfig('umd', undefined, true),
  125. 'umd-min': genConfig('umd', 'umd.min')
  126. }
  127. const formatArray = (formats + '').split(',')
  128. const configs = formatArray.map(format => configMap[format])
  129. if (configs.indexOf(undefined) !== -1) {
  130. const unknownFormats = formatArray.filter(f => configMap[f] === undefined).join(', ')
  131. abort(
  132. `Unknown library build formats: ${unknownFormats}`
  133. )
  134. }
  135. return configs
  136. }