resolveLibConfig.js 4.3 KB

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