9 changed files with 576 additions and 0 deletions
After Width: | Height: | Size: 7.9 KiB |
@ -0,0 +1,32 @@ |
|||||
|
/** |
||||
|
* 用于自动生成前端组件 |
||||
|
* 通过 src/routes/routes.json 文件构建 src/components/index.ts 文件 |
||||
|
*/ |
||||
|
const fs = require('fs'); |
||||
|
const Json5 =require('json5'); |
||||
|
|
||||
|
// 解析前端路由配置文件 |
||||
|
const routesJson = Json5.parse(fs.readFileSync('./src/routes/routes.json', 'utf8')); |
||||
|
|
||||
|
let content =''; |
||||
|
content +='/**\n'; |
||||
|
content +=' * 此文件为自动生成文件,请勿修改\n'; |
||||
|
content +=' */\n\n'; |
||||
|
for(const route of routesJson){ |
||||
|
const componentName =route.component.substring(route.component.lastIndexOf('.')+1); |
||||
|
const componentPath =route.componentPath; |
||||
|
content +=`import ${componentName} from '${componentPath}';\n`; |
||||
|
} |
||||
|
|
||||
|
content +='\n'; |
||||
|
content +='const localComponents = { \n'; |
||||
|
for(const route of routesJson){ |
||||
|
const componentName =route.component.substring(route.component.lastIndexOf('.')+1); |
||||
|
content +=`'${route.component}': ${componentName},\n`; |
||||
|
} |
||||
|
content +='}\n\n'; |
||||
|
content +='export default localComponents;\n'; |
||||
|
|
||||
|
fs.writeFileSync('./src/components/index.ts', content); |
||||
|
|
||||
|
console.info('components generated!'); |
@ -0,0 +1,173 @@ |
|||||
|
/** |
||||
|
* 用于将前端模块注册到后端服务器 |
||||
|
*/ |
||||
|
const packageJson = require('./package.json'); |
||||
|
const { ModuleFederationPlugin } = require('webpack').container; |
||||
|
const Server = require('webpack-dev-server'); |
||||
|
const mf = require('./webpack.config.mf.cjs'); |
||||
|
const fs = require('fs'); |
||||
|
const http = require('http'); |
||||
|
const https = require('https'); |
||||
|
const Json5 =require('json5'); |
||||
|
|
||||
|
// 解析前端注册器配置文件 |
||||
|
const frontendRegisterConfigure = Json5.parse(fs.readFileSync('./frontend-register.json', 'utf8')); |
||||
|
// 解析前端路由配置文件 |
||||
|
const frontendRoutes =Json5.parse(fs.readFileSync('./src/routes/routes.json', 'utf8')); |
||||
|
|
||||
|
/** |
||||
|
* 远程组件注册器类 |
||||
|
*/ |
||||
|
class RemoteFrontEndModuleRegister { |
||||
|
/** |
||||
|
* 构造函数,传入配置信息, 包括远程和本地服务器配置信息 |
||||
|
* 配置信息定义格式如下: |
||||
|
* // 远程服务器配置信息 |
||||
|
* remoteServerConfig: { |
||||
|
* protocol: 'http', |
||||
|
* host: 'localhost', |
||||
|
* port: 8080, |
||||
|
* path: '/api/system/frontend/regist', |
||||
|
* }, |
||||
|
* // 本地服务器配置信息 |
||||
|
* localServerConfig: { |
||||
|
* protocol: devServer.options.server.type, |
||||
|
* host: Server.internalIPSync("v4"), |
||||
|
* port: devServer.options.port, |
||||
|
* path: '/', |
||||
|
* } |
||||
|
* @param devServer webpack dev server 对象 |
||||
|
*/ |
||||
|
constructor(devServer) { |
||||
|
if (!devServer) { |
||||
|
throw new Error('webpack-dev-server is not defined'); |
||||
|
} |
||||
|
this.devServer = devServer; |
||||
|
this.registSuccess = null; |
||||
|
this.remoteServerConfig = { |
||||
|
protocol: frontendRegisterConfigure.protocol, |
||||
|
host: frontendRegisterConfigure.host, |
||||
|
port: frontendRegisterConfigure.port, |
||||
|
path: frontendRegisterConfigure.path, |
||||
|
}; |
||||
|
this.localServerConfig = { |
||||
|
protocol: devServer.options.server.type, |
||||
|
host: Server.internalIPSync("v4"), |
||||
|
port: devServer.options.port, |
||||
|
path: '/', |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 周期性向服务器注册前端模块 |
||||
|
* @param delay 延迟执行(单位:毫秒) |
||||
|
* @param interval 固定频率执行(单位:毫秒) |
||||
|
*/ |
||||
|
regist(delay,interval) { |
||||
|
if(frontendRegisterConfigure.enable){ |
||||
|
setTimeout(() => { |
||||
|
let remoteServerUrl = this.remoteServerConfig.protocol + '//' + this.remoteServerConfig.host + ':' + this.remoteServerConfig.port + this.remoteServerConfig.path; |
||||
|
console.info('regist frontend module to server --> ' + remoteServerUrl); |
||||
|
setInterval(this.doRegist.bind(this), delay); |
||||
|
}, delay); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 向服务器注册前端模块 |
||||
|
*/ |
||||
|
doRegist() { |
||||
|
const data = JSON.stringify(this.getRegistJson()); |
||||
|
if (data) { |
||||
|
let request = this.getRequest(this.remoteServerConfig.protocol); |
||||
|
let This = this; |
||||
|
request.on('error', error => { |
||||
|
if (This.registSuccess == null || This.registSuccess) { |
||||
|
This.registSuccess = false; |
||||
|
console.error('regist frontend module to server, Failed!', error); |
||||
|
} |
||||
|
}); |
||||
|
request.write(data); |
||||
|
request.end(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取前端模块的注册信息 |
||||
|
* @returns 前端模块的注册信息 |
||||
|
*/ |
||||
|
getRegistJson() { |
||||
|
return { |
||||
|
protocol: this.localServerConfig.protocol, |
||||
|
host: this.localServerConfig.host, |
||||
|
port: this.localServerConfig.port, |
||||
|
contextPath: this.localServerConfig.contextPath, |
||||
|
name: packageJson.name, |
||||
|
components: this.getComponents(), |
||||
|
routes: frontendRoutes, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取前端模块的注册信息(组件集合) |
||||
|
* @returns 前端模块的注册信息(组件集合) |
||||
|
*/ |
||||
|
getComponents() { |
||||
|
const plugins = mf.plugins; |
||||
|
for (let i = 0; i < plugins.length; i++) { |
||||
|
const plugin = plugins[i]; |
||||
|
if (plugin instanceof ModuleFederationPlugin) { |
||||
|
const exposes = plugin._options.exposes; |
||||
|
if (exposes) { |
||||
|
const components = []; |
||||
|
let keyIndex = 0; |
||||
|
for (let key in exposes) { |
||||
|
components[keyIndex] = key; |
||||
|
keyIndex++; |
||||
|
} |
||||
|
return components; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取 http/https 请求 |
||||
|
* @param {*} protocol 请求协议 |
||||
|
*/ |
||||
|
getRequest(protocol) { |
||||
|
let request = http; |
||||
|
if (protocol == 'https:') { |
||||
|
request = https; |
||||
|
} |
||||
|
let This = this; |
||||
|
return request.request({ |
||||
|
protocol: this.remoteServerConfig.protocol + ":", |
||||
|
host: this.remoteServerConfig.host, |
||||
|
port: this.remoteServerConfig.port, |
||||
|
path: this.remoteServerConfig.path, |
||||
|
method: 'POST', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json' |
||||
|
} |
||||
|
}, request => { |
||||
|
request.setEncoding('utf-8'); |
||||
|
request.on('data', d => { |
||||
|
const data = JSON.parse(d); |
||||
|
if (data.code === 200) { |
||||
|
if (This.registSuccess == null || !This.registSuccess) { |
||||
|
This.registSuccess = true; |
||||
|
console.info('regist frontend module to server, Success!'); |
||||
|
} |
||||
|
} else { |
||||
|
console.error('regist frontend module to server, Failed!', d); |
||||
|
} |
||||
|
}) |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
module.exports = { |
||||
|
RemoteFrontEndModuleRegister |
||||
|
} |
@ -0,0 +1,159 @@ |
|||||
|
/** |
||||
|
* webpack 通用配置 |
||||
|
*/ |
||||
|
const path = require('path'); // path |
||||
|
const webpack = require('webpack'); // webpack |
||||
|
const json5 = require('json5'); // json5 |
||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin'); // webpack html 生成插件 |
||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin'); // webpack copy 插件 |
||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 抽取 css 插件 |
||||
|
const { VueLoaderPlugin } = require('vue-loader'); // vue loader 插件 |
||||
|
const ESLintPlugin = require('eslint-webpack-plugin'); // eslint 插件 |
||||
|
const packageJson = require('./package.json'); // package.json |
||||
|
const projectName =packageJson.name; // 项目名称 |
||||
|
|
||||
|
module.exports = { |
||||
|
// 入口文件 |
||||
|
entry: './src/main', |
||||
|
// 输出 |
||||
|
output: { |
||||
|
// 输出路径(为兼容后端和多个前端项目) |
||||
|
// 1. 兼容后端: 将 dist 目录作为资源目录, 其中 public 种的静态资源可以直接访问 |
||||
|
// 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录 |
||||
|
path: path.resolve(__dirname, `dist/public/${projectName}`), |
||||
|
// 输出文件名 |
||||
|
filename: `javascript/[name].[contenthash:5].js`, |
||||
|
// 指定发布路径,使用 auto 可具有更多灵活性 |
||||
|
publicPath: 'auto', |
||||
|
// 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果 |
||||
|
clean: true, |
||||
|
}, |
||||
|
|
||||
|
module: { |
||||
|
rules: [ |
||||
|
// babel(包含处理: typescript) |
||||
|
{ |
||||
|
test: /\.(t|j)s$/, |
||||
|
exclude: /node_modules/, |
||||
|
use: [ |
||||
|
{ |
||||
|
loader: "babel-loader", |
||||
|
options: { |
||||
|
cacheDirectory: true, |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
// css |
||||
|
{ |
||||
|
test: /\.(sa|sc|c)ss$/, |
||||
|
use: [{ |
||||
|
loader: MiniCssExtractPlugin.loader, |
||||
|
}, |
||||
|
{ |
||||
|
loader: 'css-loader', |
||||
|
}, |
||||
|
{ |
||||
|
loader: 'postcss-loader', |
||||
|
}] |
||||
|
}, |
||||
|
|
||||
|
// 字体文件 |
||||
|
{ |
||||
|
test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/, |
||||
|
type: 'asset/resource', |
||||
|
generator: { |
||||
|
filename: `fonts/[name].[contenthash:5].[ext]`, |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// json5 |
||||
|
{ |
||||
|
test: /\.json$/, |
||||
|
type: 'json', |
||||
|
parser: { |
||||
|
parse: json5.parse, |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
// vue loader |
||||
|
{ |
||||
|
test: /\.vue$/, |
||||
|
exclude: /node_modules/, |
||||
|
use: [ |
||||
|
{ |
||||
|
loader: 'vue-loader', |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
|
||||
|
// 插件 |
||||
|
plugins: [ |
||||
|
new webpack.DefinePlugin({ |
||||
|
__VUE_OPTIONS_API__: JSON.stringify(true), |
||||
|
__VUE_PROD_DEVTOOLS__: JSON.stringify(false) |
||||
|
}), |
||||
|
|
||||
|
// 进度显示插件 |
||||
|
new webpack.ProgressPlugin(), |
||||
|
|
||||
|
// css 抽取插件 |
||||
|
new MiniCssExtractPlugin({ |
||||
|
filename: `css/[name].[contenthash:5].css`, |
||||
|
chunkFilename: `css/[name].[contenthash:5].css` |
||||
|
}), |
||||
|
|
||||
|
// 自动生成静态 index.html 文件 |
||||
|
new HtmlWebpackPlugin({ |
||||
|
template: 'public/index.html', |
||||
|
filename: `index.html`, |
||||
|
minify: false, |
||||
|
inject: 'body', |
||||
|
timestamp: new Date().getTime(), |
||||
|
}), |
||||
|
|
||||
|
// 拷贝静态资源到 output.path 指定的目录 |
||||
|
new CopyWebpackPlugin({ |
||||
|
patterns: [ |
||||
|
{ |
||||
|
from: 'public', |
||||
|
toType: 'dir', |
||||
|
filter: async (resourcePath) => { |
||||
|
// 不复制 index.html 因为 index.html 已经由 HtmlWebpackPlugin 插件生成了 |
||||
|
if (resourcePath.endsWith('index.html') || resourcePath.endsWith('.DS_Store')) { |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
}, |
||||
|
info: { minimized: true }, |
||||
|
} |
||||
|
] |
||||
|
}), |
||||
|
|
||||
|
// vue loader 插件 |
||||
|
new VueLoaderPlugin(), |
||||
|
|
||||
|
// eslint 插件 |
||||
|
new ESLintPlugin({ |
||||
|
fix: true, |
||||
|
formatter: 'stylish', |
||||
|
extensions: ['js', 'ts', 'vue', 'cjs'], |
||||
|
exclude: [ |
||||
|
'node_modules', |
||||
|
], |
||||
|
}), |
||||
|
], |
||||
|
|
||||
|
// 配置模块如何被解析, |
||||
|
resolve: { |
||||
|
// 设置模块别名,方便引用 |
||||
|
alias: { |
||||
|
'@': path.resolve(__dirname, 'src'), |
||||
|
}, |
||||
|
// 设置支持的模块扩展名,即这些扩展名的文件可以作为模块被使用 |
||||
|
extensions: ['.ts', '.js', '.cjs', '.vue'] |
||||
|
}, |
||||
|
}; |
@ -0,0 +1,66 @@ |
|||||
|
/** |
||||
|
* webpack module federation 配置 |
||||
|
*/ |
||||
|
const fs = require('fs'); // 文件读取 |
||||
|
const Json5 =require('json5'); // json5 |
||||
|
const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 |
||||
|
const packageJson = require('./package.json'); // package.json |
||||
|
const projectName =packageJson.name; // 项目名称 |
||||
|
const deps = packageJson.dependencies; // 项目依赖 |
||||
|
|
||||
|
// 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值 |
||||
|
const data = fs.readFileSync('./src/routes/routes.json', 'utf8'); |
||||
|
const routes =Json5.parse(data); |
||||
|
const mfExposes ={}; |
||||
|
for(const route of routes){ |
||||
|
mfExposes[route.component]= route.componentPath; |
||||
|
} |
||||
|
|
||||
|
// 导出 webapck 配置的模块联邦部分 |
||||
|
module.exports = { |
||||
|
plugins: [ |
||||
|
new ModuleFederationPlugin({ |
||||
|
// 模块联邦的模块名称 |
||||
|
name: `${projectName}`, |
||||
|
// 模块联邦的远程入口文件 |
||||
|
filename: `javascript/remoteEntry.js`, |
||||
|
// 通过浏览器 window 对象保存模块联邦对象 |
||||
|
library: { type: 'window', name: `${projectName}` }, |
||||
|
remoteType: 'window', |
||||
|
// 模块联邦的导出组件 |
||||
|
exposes: mfExposes, |
||||
|
// 模块联邦共享库 |
||||
|
shared: { |
||||
|
'@codemirror/autocomplete': { requiredVersion: deps['@codemirror/autocomplete'], singleton: true }, |
||||
|
'@codemirror/commands': { requiredVersion: deps['@codemirror/commands'], singleton: true }, |
||||
|
'@codemirror/lang-html': { requiredVersion: deps['@codemirror/lang-html'], singleton: true }, |
||||
|
'@codemirror/lang-java': { requiredVersion: deps['@codemirror/lang-java'], singleton: true }, |
||||
|
'@codemirror/lang-javascript': { requiredVersion: deps['@codemirror/lang-javascript'], singleton: true }, |
||||
|
'@codemirror/lang-json': { requiredVersion: deps['@codemirror/lang-json'], singleton: true }, |
||||
|
'@codemirror/lang-sql': { requiredVersion: deps['@codemirror/lang-sql'], singleton: true }, |
||||
|
'@codemirror/lang-xml': { requiredVersion: deps['@codemirror/lang-xml'], singleton: true }, |
||||
|
'@codemirror/language': { requiredVersion: deps['@codemirror/language'], singleton: true }, |
||||
|
'@codemirror/search': { requiredVersion: deps['@codemirror/search'], singleton: true }, |
||||
|
'@codemirror/state': { requiredVersion: deps['@codemirror/state'], singleton: true }, |
||||
|
'@codemirror/view': { requiredVersion: deps['@codemirror/view'], singleton: true }, |
||||
|
'@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true }, |
||||
|
'axios': { requiredVersion: deps['axios'], singleton: true }, |
||||
|
'codemirror': { requiredVersion: deps['codemirror'], singleton: true }, |
||||
|
'dayjs': { requiredVersion: deps['dayjs'], singleton: true }, |
||||
|
'echarts':{ requiredVersion: deps['echarts'], singleton: true }, |
||||
|
'exceljs':{ requiredVersion: deps['exceljs'], singleton: true }, |
||||
|
'file-saver':{ requiredVersion: deps['file-saver'], singleton: true }, |
||||
|
'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true }, |
||||
|
"mockjs": { requiredVersion: deps['mockjs'], singleton: true }, |
||||
|
'pinia': { requiredVersion: deps['pinia'], singleton: true }, |
||||
|
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, |
||||
|
'quasar': { requiredVersion: deps['quasar'], singleton: true }, |
||||
|
'vue': { requiredVersion: deps['vue'], singleton: true }, |
||||
|
'vue-codemirror6': { requiredVersion: deps['vue-codemirror6'], singleton: true }, |
||||
|
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, |
||||
|
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, |
||||
|
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, |
||||
|
} |
||||
|
}), |
||||
|
] |
||||
|
}; |
@ -0,0 +1,76 @@ |
|||||
|
/** |
||||
|
* 开发环境构建 |
||||
|
*/ |
||||
|
const { merge } = require('webpack-merge'); // webpack 配置合并函数 |
||||
|
const common = require('./webpack.config.common.cjs'); // webpack 通用配置 |
||||
|
const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 |
||||
|
|
||||
|
module.exports = merge(common, mf, { |
||||
|
mode: 'development', |
||||
|
// ------------------------------------------------------------------------------------------------------------------------------- |
||||
|
// devtool | performance | comment |
||||
|
// (none) | build:fastest, rebuild:fastest | Recommended choice for production builds with maximum performance. |
||||
|
// eval | build:fast, rebuild:fastest | Recommended choice for development builds with maximum performance. |
||||
|
// eval-source-map| build:slowest, rebuild:ok | Recommended choice for development builds with high quality SourceMaps. |
||||
|
// source-map | build:slowest, rebuild:slowest | Recommended choice for production builds with high quality SourceMaps. |
||||
|
// ------------------------------------------------------------------------------------------------------------------------------- |
||||
|
devtool: 'eval-source-map', |
||||
|
optimization: { |
||||
|
minimize: false, |
||||
|
moduleIds: 'named', |
||||
|
chunkIds: 'named', |
||||
|
|
||||
|
splitChunks: { |
||||
|
cacheGroups: { |
||||
|
'vue': { |
||||
|
name: 'vue', |
||||
|
test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router)[\\/]/, |
||||
|
priority: 20, |
||||
|
chunks: 'all', |
||||
|
enforce: true |
||||
|
}, |
||||
|
'dnd':{ |
||||
|
name: 'dnd', |
||||
|
test: /[\\/]node_modules[\\/](vue3-dnd|react-dnd-html5-backend|@vueuse[\\/]core)[\\/]/, |
||||
|
priority: 20, |
||||
|
chunks: 'all', |
||||
|
enforce: true |
||||
|
}, |
||||
|
'quasar': { |
||||
|
name: 'quasar', |
||||
|
test: /[\\/]node_modules[\\/](quasar)[\\/]/, |
||||
|
priority: 20, |
||||
|
chunks: 'all', |
||||
|
enforce: true |
||||
|
}, |
||||
|
'excel': { |
||||
|
name: 'excel', |
||||
|
test: /[\\/]node_modules[\\/](exceljs|luckyexcel|)[\\/]/, |
||||
|
priority: 20, |
||||
|
chunks: 'all', |
||||
|
enforce: true |
||||
|
}, |
||||
|
'platform-core': { |
||||
|
name: 'platform-core', |
||||
|
test: /[\\/]node_modules[\\/]platform-core[\\/]/, |
||||
|
priority: 20, |
||||
|
chunks: 'all', |
||||
|
enforce: true |
||||
|
}, |
||||
|
'view': { |
||||
|
name: 'view', |
||||
|
test: /[\\/]view[\\/]/, |
||||
|
priority: 20, |
||||
|
chunks: 'all', |
||||
|
enforce: true |
||||
|
}, |
||||
|
'vendors': { |
||||
|
name: 'vendors', |
||||
|
test: /[\\/]node_modules[\\/]/, |
||||
|
chunks: 'all', |
||||
|
enforce: true |
||||
|
}, |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
}); |
@ -0,0 +1,35 @@ |
|||||
|
/** |
||||
|
* 生产环境构建 |
||||
|
*/ |
||||
|
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); // css 压缩插件 |
||||
|
const TerserPlugin = require("terser-webpack-plugin"); // js 压缩插件 |
||||
|
const { merge } = require('webpack-merge'); // webpack 配置合并函数 |
||||
|
const build = require('./webpack.env.build.cjs'); // 开发环境构建配置 |
||||
|
|
||||
|
module.exports = merge(build, { |
||||
|
mode: 'production', |
||||
|
// ------------------------------------------------------------------------------------------------------------------------------- |
||||
|
// devtool | performance | comment |
||||
|
// (none) | build:fastest, rebuild:fastest | Recommended choice for production builds with maximum performance. |
||||
|
// eval | build:fast, rebuild:fastest | Recommended choice for development builds with maximum performance. |
||||
|
// eval-source-map| build:slowest, rebuild:ok | Recommended choice for development builds with high quality SourceMaps. |
||||
|
// source-map | build:slowest, rebuild:slowest | Recommended choice for production builds with high quality SourceMaps. |
||||
|
// ------------------------------------------------------------------------------------------------------------------------------- |
||||
|
devtool: 'source-map', |
||||
|
optimization: { |
||||
|
minimize: true, |
||||
|
minimizer: [ |
||||
|
new CssMinimizerPlugin(), // css 压缩插件 |
||||
|
new TerserPlugin({ // js 压缩插件 |
||||
|
extractComments: false, |
||||
|
terserOptions: { |
||||
|
format: { |
||||
|
comments: false, |
||||
|
}, |
||||
|
}, |
||||
|
}), |
||||
|
], |
||||
|
moduleIds: 'named', |
||||
|
chunkIds: 'named', |
||||
|
}, |
||||
|
}); |
@ -0,0 +1,35 @@ |
|||||
|
/** |
||||
|
* 开发环境下启动 webpack dev server |
||||
|
*/ |
||||
|
const path = require('path'); // path |
||||
|
const { merge } = require('webpack-merge'); // webpack 配置合并函数 |
||||
|
const common = require('./webpack.config.common.cjs'); // webpack 通用配置 |
||||
|
const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 |
||||
|
const { RemoteFrontEndModuleRegister } = require('./util-frontend-register.cjs'); // 远程模块注册器 |
||||
|
|
||||
|
module.exports = (env)=> merge(common, mf,{ |
||||
|
mode: 'development', |
||||
|
devtool: 'eval', |
||||
|
|
||||
|
devServer: { |
||||
|
client: { |
||||
|
overlay: false, |
||||
|
}, |
||||
|
static: { |
||||
|
directory: path.join(__dirname, 'public'), |
||||
|
}, |
||||
|
compress: false, |
||||
|
port: 3000, |
||||
|
hot: true, |
||||
|
// 保证在出现 404 错误时,能够导航到 index.html |
||||
|
historyApiFallback: true, |
||||
|
|
||||
|
setupMiddlewares: (middlewares, devServer) => { |
||||
|
// 注册前端模块到远程服务器 |
||||
|
const register = new RemoteFrontEndModuleRegister(devServer); |
||||
|
// 延后 5 秒执行, 且每 5 秒执行一次 |
||||
|
register.regist(5000,5000); |
||||
|
return middlewares; |
||||
|
} |
||||
|
}, |
||||
|
}); |
Loading…
Reference in new issue