webpack.common.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /* eslint-disable camelcase */
  2. const { VueLoaderPlugin } = require('vue-loader')
  3. const path = require('path')
  4. const BabelLoaderExcludeNodeModulesExcept = require('babel-loader-exclude-node-modules-except')
  5. const webpack = require('webpack')
  6. const modules = require('./webpack.modules.js')
  7. const formatOutputFromModules = (modules) => {
  8. // merge all configs into one object, and use AppID to generate the fileNames
  9. // with the following format:
  10. // AppId-fileName: path/to/js-file.js
  11. const moduleEntries = Object.keys(modules).map(moduleKey => {
  12. const module = modules[moduleKey]
  13. const entries = Object.keys(module).map(entryKey => {
  14. const entry = module[entryKey]
  15. return { [`${moduleKey}-${entryKey}`]: entry }
  16. })
  17. return Object.assign({}, ...Object.values(entries))
  18. })
  19. return Object.assign({}, ...Object.values(moduleEntries))
  20. }
  21. const modulesToBuild = () => {
  22. const MODULE = process?.env?.MODULE
  23. if (MODULE) {
  24. if (!modules[MODULE]) {
  25. throw new Error(`No module "${MODULE}" found`)
  26. }
  27. return formatOutputFromModules({
  28. [MODULE]: modules[MODULE],
  29. })
  30. }
  31. return formatOutputFromModules(modules)
  32. }
  33. module.exports = {
  34. entry: modulesToBuild(),
  35. output: {
  36. // Step away from the src folder and extract to the js folder
  37. path: path.join(__dirname, 'dist'),
  38. // Let webpack determine automatically where it's located
  39. publicPath: 'auto',
  40. filename: '[name].js?v=[contenthash]',
  41. chunkFilename: '[name]-[id].js?v=[contenthash]',
  42. // Make sure sourcemaps have a proper path and do not
  43. // leak local paths https://github.com/webpack/webpack/issues/3603
  44. devtoolNamespace: 'nextcloud',
  45. devtoolModuleFilenameTemplate(info) {
  46. const rootDir = process?.cwd()
  47. const rel = path.relative(rootDir, info.absoluteResourcePath)
  48. return `webpack:///nextcloud/${rel}`
  49. },
  50. clean: {
  51. keep: /icons\.css/, // Keep static icons css
  52. },
  53. },
  54. module: {
  55. rules: [
  56. {
  57. test: /davclient/,
  58. loader: 'exports-loader',
  59. options: {
  60. type: 'commonjs',
  61. exports: 'dav',
  62. },
  63. },
  64. {
  65. test: /\.css$/,
  66. use: ['style-loader', 'css-loader'],
  67. },
  68. {
  69. test: /\.scss$/,
  70. use: ['style-loader', 'css-loader', 'sass-loader'],
  71. },
  72. {
  73. test: /\.vue$/,
  74. loader: 'vue-loader',
  75. exclude: BabelLoaderExcludeNodeModulesExcept([
  76. 'vue-material-design-icons',
  77. 'emoji-mart-vue-fast',
  78. ]),
  79. },
  80. {
  81. test: /\.tsx?$/,
  82. use: 'babel-loader',
  83. exclude: BabelLoaderExcludeNodeModulesExcept([]),
  84. },
  85. {
  86. test: /\.js$/,
  87. loader: 'babel-loader',
  88. // automatically detect necessary packages to
  89. // transpile in the node_modules folder
  90. exclude: BabelLoaderExcludeNodeModulesExcept([
  91. '@nextcloud/dialogs',
  92. '@nextcloud/event-bus',
  93. '@nextcloud/vue-dashboard',
  94. 'davclient.js',
  95. 'nextcloud-vue-collections',
  96. 'p-finally',
  97. 'p-limit',
  98. 'p-locate',
  99. 'p-queue',
  100. 'p-timeout',
  101. 'p-try',
  102. 'semver',
  103. 'striptags',
  104. 'toastify-js',
  105. 'v-tooltip',
  106. 'yocto-queue',
  107. ]),
  108. },
  109. {
  110. test: /\.(png|jpe?g|gif|svg|woff2?|eot|ttf)$/,
  111. type: 'asset/inline',
  112. },
  113. {
  114. test: /\.handlebars/,
  115. loader: 'handlebars-loader',
  116. },
  117. {
  118. resourceQuery: /raw/,
  119. type: 'asset/source',
  120. },
  121. ],
  122. },
  123. optimization: {
  124. splitChunks: {
  125. automaticNameDelimiter: '-',
  126. cacheGroups: {
  127. vendors: {
  128. // split every dependency into one bundle
  129. test: /[\\/]node_modules[\\/]/,
  130. enforce: true,
  131. // necessary to keep this name to properly inject it
  132. // see OC_Template.php
  133. name: 'core-common',
  134. chunks: 'all',
  135. },
  136. },
  137. },
  138. },
  139. plugins: [
  140. new VueLoaderPlugin(),
  141. new webpack.ProvidePlugin({
  142. // Provide jQuery to jquery plugins as some are loaded before $ is exposed globally.
  143. // We need to provide the path to node_moduels as otherwise npm link will fail due
  144. // to tribute.js checking for jQuery in @nextcloud/vue
  145. jQuery: path.resolve(path.join(__dirname, 'node_modules/jquery')),
  146. // Shim ICAL to prevent using the global object (window.ICAL).
  147. // The library ical.js heavily depends on instanceof checks which will
  148. // break if two separate versions of the library are used (e.g. bundled one
  149. // and global one).
  150. ICAL: 'ical.js',
  151. // https://github.com/webpack/changelog-v5/issues/10
  152. Buffer: ['buffer', 'Buffer'],
  153. }),
  154. ],
  155. externals: {
  156. OC: 'OC',
  157. OCA: 'OCA',
  158. OCP: 'OCP',
  159. },
  160. resolve: {
  161. alias: {
  162. // make sure to use the handlebar runtime when importing
  163. handlebars: 'handlebars/runtime',
  164. },
  165. extensions: ['*', '.ts', '.js', '.vue'],
  166. symlinks: true,
  167. fallback: {
  168. buffer: require.resolve('buffer'),
  169. fs: false,
  170. stream: require.resolve('stream-browserify'),
  171. },
  172. },
  173. }