123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- /* eslint-disable camelcase */
- /**
- * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
- const { VueLoaderPlugin } = require('vue-loader')
- const path = require('path')
- const BabelLoaderExcludeNodeModulesExcept = require('babel-loader-exclude-node-modules-except')
- const webpack = require('webpack')
- const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
- const WorkboxPlugin = require('workbox-webpack-plugin')
- const modules = require('./webpack.modules.js')
- const { readFileSync } = require('fs')
- const appVersion = readFileSync('./version.php').toString().match(/OC_VersionString[^']+'([^']+)/)?.[1] ?? 'unknown'
- const formatOutputFromModules = (modules) => {
- // merge all configs into one object, and use AppID to generate the fileNames
- // with the following format:
- // AppId-fileName: path/to/js-file.js
- const moduleEntries = Object.keys(modules).map(moduleKey => {
- const module = modules[moduleKey]
- const entries = Object.keys(module).map(entryKey => {
- const entry = module[entryKey]
- return { [`${moduleKey}-${entryKey}`]: entry }
- })
- return Object.assign({}, ...Object.values(entries))
- })
- return Object.assign({}, ...Object.values(moduleEntries))
- }
- const modulesToBuild = () => {
- const MODULE = process?.env?.MODULE
- if (MODULE) {
- if (!modules[MODULE]) {
- throw new Error(`No module "${MODULE}" found`)
- }
- return formatOutputFromModules({
- [MODULE]: modules[MODULE],
- })
- }
- return formatOutputFromModules(modules)
- }
- module.exports = {
- entry: modulesToBuild(),
- output: {
- // Step away from the src folder and extract to the js folder
- path: path.join(__dirname, 'dist'),
- // Let webpack determine automatically where it's located
- publicPath: 'auto',
- filename: '[name].js?v=[contenthash]',
- chunkFilename: '[name]-[id].js?v=[contenthash]',
- // Make sure sourcemaps have a proper path and do not
- // leak local paths https://github.com/webpack/webpack/issues/3603
- devtoolNamespace: 'nextcloud',
- devtoolModuleFilenameTemplate(info) {
- const rootDir = process?.cwd()
- const rel = path.relative(rootDir, info.absoluteResourcePath)
- return `webpack:///nextcloud/${rel}`
- },
- clean: {
- keep: /icons\.css/, // Keep static icons css
- },
- },
- module: {
- rules: [
- {
- test: /davclient/,
- loader: 'exports-loader',
- options: {
- type: 'commonjs',
- exports: 'dav',
- },
- },
- {
- test: /\.css$/,
- use: ['style-loader', 'css-loader'],
- },
- {
- test: /\.scss$/,
- use: ['style-loader', 'css-loader', 'sass-loader'],
- },
- {
- test: /\.vue$/,
- loader: 'vue-loader',
- exclude: BabelLoaderExcludeNodeModulesExcept([
- 'vue-material-design-icons',
- 'emoji-mart-vue-fast',
- ]),
- },
- {
- test: /\.tsx?$/,
- use: [
- 'babel-loader',
- {
- // Fix TypeScript syntax errors in Vue
- loader: 'ts-loader',
- options: {
- transpileOnly: true,
- },
- },
- ],
- exclude: BabelLoaderExcludeNodeModulesExcept([]),
- },
- {
- test: /\.js$/,
- loader: 'babel-loader',
- // automatically detect necessary packages to
- // transpile in the node_modules folder
- exclude: BabelLoaderExcludeNodeModulesExcept([
- '@nextcloud/dialogs',
- '@nextcloud/event-bus',
- 'davclient.js',
- 'nextcloud-vue-collections',
- 'p-finally',
- 'p-limit',
- 'p-locate',
- 'p-queue',
- 'p-timeout',
- 'p-try',
- 'semver',
- 'striptags',
- 'toastify-js',
- 'v-tooltip',
- 'yocto-queue',
- ]),
- },
- {
- test: /\.(png|jpe?g|gif|svg|woff2?|eot|ttf)$/,
- type: 'asset/inline',
- },
- {
- test: /\.handlebars/,
- loader: 'handlebars-loader',
- },
- {
- resourceQuery: /raw/,
- type: 'asset/source',
- },
- ],
- },
- optimization: {
- minimizer: [{
- apply: (compiler) => {
- // Lazy load the Terser plugin
- const TerserPlugin = require('terser-webpack-plugin')
- new TerserPlugin({
- extractComments: {
- condition: /^\**!|@license|@copyright|SPDX-License-Identifier|SPDX-FileCopyrightText/i,
- filename: (fileData) => {
- // The "fileData" argument contains object with "filename", "basename", "query" and "hash"
- return `${fileData.filename}.license${fileData.query}`
- },
- },
- terserOptions: {
- compress: {
- passes: 2,
- },
- },
- }).apply(compiler)
- },
- }],
- splitChunks: {
- automaticNameDelimiter: '-',
- minChunks: 3, // minimum number of chunks that must share the module
- cacheGroups: {
- vendors: {
- // split every dependency into one bundle
- test: /[\\/]node_modules[\\/]/,
- // necessary to keep this name to properly inject it
- // see OC_Template.php
- name: 'core-common',
- chunks: 'all',
- },
- },
- },
- },
- plugins: [
- new VueLoaderPlugin(),
- new NodePolyfillPlugin(),
- new webpack.ProvidePlugin({
- // Provide jQuery to jquery plugins as some are loaded before $ is exposed globally.
- // We need to provide the path to node_moduels as otherwise npm link will fail due
- // to tribute.js checking for jQuery in @nextcloud/vue
- jQuery: path.resolve(path.join(__dirname, 'node_modules/jquery')),
- }),
- new WorkboxPlugin.GenerateSW({
- swDest: 'preview-service-worker.js',
- clientsClaim: true,
- skipWaiting: true,
- exclude: [/.*/], // don't do pre-caching
- inlineWorkboxRuntime: true,
- sourcemap: false,
- // Increase perfs with less logging
- disableDevLogs: true,
- // Define runtime caching rules.
- runtimeCaching: [{
- // Match any preview file request
- // /apps/files_trashbin/preview?fileId=156380&a=1
- // /core/preview?fileId=155842&a=1
- urlPattern: /^.*\/(apps|core)(\/[a-z-_]+)?\/preview.*/i,
- // Apply a strategy.
- handler: 'CacheFirst',
- options: {
- // Use a custom cache name.
- cacheName: 'previews',
- // Only cache 10000 images.
- expiration: {
- maxAgeSeconds: 3600 * 24 * 7, // one week
- maxEntries: 10000,
- },
- },
- }],
- }),
- // Make appName & appVersion available as a constants for '@nextcloud/vue' components
- new webpack.DefinePlugin({ appName: JSON.stringify('Nextcloud') }),
- new webpack.DefinePlugin({ appVersion: JSON.stringify(appVersion) }),
- // @nextcloud/moment since v1.3.0 uses `moment/min/moment-with-locales.js`
- // Which works only in Node.js and is not compatible with Webpack bundling
- // It has an unused function `localLocale` that requires locales by invalid relative path `./locale`
- // Though it is not used, Webpack tries to resolve it with `require.context` and fails
- new webpack.IgnorePlugin({
- resourceRegExp: /^\.\/locale$/,
- contextRegExp: /moment\/min$/,
- }),
- ],
- externals: {
- OC: 'OC',
- OCA: 'OCA',
- OCP: 'OCP',
- },
- resolve: {
- alias: {
- // make sure to use the handlebar runtime when importing
- handlebars: 'handlebars/runtime',
- vue$: path.resolve('./node_modules/vue'),
- },
- extensions: ['*', '.ts', '.js', '.vue'],
- extensionAlias: {
- /**
- * Resolve TypeScript files when using fully-specified esm import paths
- * https://github.com/webpack/webpack/issues/13252
- */
- '.js': ['.js', '.ts'],
- },
- symlinks: true,
- fallback: {
- fs: false,
- },
- },
- }
|