/* eslint-disable filenames/match-regex */ const path = require('path') const webpack = require('webpack') const AliasPlugin = require('enhanced-resolve/lib/AliasPlugin') const CircularDependencyPlugin = require('circular-dependency-plugin') const { argv } = require('yargs') const openInEditor = require('launch-editor-middleware') const designVariables = require('./src/common/design/variables.js') function isInSrc(context) { // 判断当前上下文是否属于src目录 const srcPath = path.resolve(__dirname, 'src') return context === srcPath || context.startsWith(srcPath + path.sep) } const replaceRelative = new webpack.NormalModuleReplacementPlugin(/^\..*/, function(resource) { // 将相对路径改写为完整路径,便于在custom和src目录搜索 const requstFullPath = path.resolve(resource.context, resource.request) // 不是src目录发起的 或 不是引用src目录的文件,退出 // 比如请求node_module下的文件时,不处理 if (!isInSrc(resource.context) || !isInSrc(requstFullPath)) return let p = path.resolve(resource.context, resource.request).replace(__dirname, '') p = p.replace(/\\/g, '/').replace('/src/', '') // console.warn('\nReplace path:', resource.request, p) resource.request = p }) const replaceAtSign = new webpack.NormalModuleReplacementPlugin(/^@.*/, function(resource) { // 将@开始的路径改写为完整路径,便于在custom和src目录搜索 if (!isInSrc(resource.context)) return const p = resource.request.replace('@/', '') // console.warn('\n@Replace path:', resource.request, p) resource.request = p }) let appConfigCustom try { appConfigCustom = require('./src_custom/app-config.js') } catch (e) { appConfigCustom = {} } const appConfig = appConfigCustom // 各种API地址,转发到后台服务器 const proxy = {} const proxySetting = { target: appConfig.apiEndpoint || 'https://192.168.2.177:8898/xcoa', secure: false, changeOrigin: true, // 转发时去掉虚拟的路径 pathRewrite: { '^/-app-': '' }, logLevel: 'debug', } const paths = ['api', 'docviewer-webapp', ...(appConfig.apiPaths || [])] paths.forEach((path) => { proxy['/-app-/' + path] = proxySetting }) process.env.VUE_APP_TITLE = appConfig.appTitle || 'GRC.Platform' module.exports = { publicPath: '', transpileDependencies: [ 'ant-design-vue', 'vue-echarts', 'resize-detector', 'signature_pad', 'sm-crypto', ], devServer: { // 本地的开发服务器也加一个app路径,模拟真实环境 // 注意访问的时候要加上这个虚拟路径,如:http://localhost:8080/-app-/ publicPath: '/-app-/', port: appConfig.devServerPort || 8080, proxy, // 处理mock数据 before(app) { app.use('/__open-in-editor', openInEditor('code')) require('./src/_mock').getBeforeHook(app) }, // 允许通过域名访问 disableHostCheck: true, // 静态资源存放的目录,如indidoc安装文件 contentBase: [path.join(__dirname, 'src_custom', 'www')], contentBasePublicPath: '/-app-', }, configureWebpack: (config) => { // sass处理器会把\xxxx转义的字符,转义回中文。用css-unicode-loader再次转成\xxxx const sassLoader = require.resolve('sass-loader') config.module.rules .filter((rule) => { if (!rule.test) return false return rule.test.toString().indexOf('scss') !== -1 }) .forEach((rule) => { rule.oneOf.forEach((oneOfRule) => { const sassLoaderIndex = oneOfRule.use.findIndex((item) => item.loader === sassLoader) oneOfRule.use.splice(sassLoaderIndex, 0, { loader: require.resolve('css-unicode-loader'), }) }) }) const plugins = [ replaceRelative, replaceAtSign, new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/), ] if (argv.analyseCircularDependency) { plugins.push( new CircularDependencyPlugin({ exclude: /node_modules/, include: /src/, failOnError: true, allowAsyncCycles: false, cwd: process.cwd(), }) ) } return { plugins, resolve: { plugins: [ new AliasPlugin( 'described-resolve', [ { name: '@extension-points', alias: [ path.resolve('src_custom', '_extension-points'), path.resolve('src', '_extension-points'), ], }, ], 'resolve' ), ], }, } }, /** * @param {import('webpack-chain')} config */ chainWebpack: (config) => { config.resolve.alias .set('@custom', path.resolve('src_custom')) .set('@product', path.resolve('src_product')) .set('@external', path.resolve('lib-external')) // 把项目定制目录放在平台目录前面,可以覆盖 config.resolve.modules.add(path.resolve(__dirname, 'src_custom/_override')) config.resolve.modules.add(path.resolve(__dirname, 'src')) config.plugin('html').tap((args) => { args[0].title = process.env.VUE_APP_TITLE args[0].primaryColor = designVariables['primary-color'] return args }) // 避免moment被打包多次的问题 config.resolve.alias.set('moment$', path.resolve(__dirname, 'node_modules/moment/moment.js')) if ((process.env.NODE_ENV === 'production' && !argv.enableSourceMap) || argv.disableSourceMap) { config.devtool('(none)') } config.plugins.delete('prefetch') config.plugins.delete('preload') }, css: { requireModuleExtension: true, loaderOptions: { css: { // js中可以使用camelCase获取classname localsConvention: 'camelCase', modules: { // css moudule 生成的class规则:原class+组件名+模块名 localIdentName: '[local]_[name]_[1]', localIdentRegExp: /src.([a-z-]*)/i, }, }, less: { modifyVars: designVariables, javascriptEnabled: true, }, }, }, }