resolveLibConfig.js 4.5 KB

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