├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── packages ├── app1 │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── src │ │ ├── assets │ │ │ └── logo.png │ │ ├── components │ │ │ └── test.vue │ │ ├── main.js │ │ ├── pages │ │ │ └── App.vue │ │ ├── shims-vue.d.ts │ │ └── store │ │ │ ├── Actions.js │ │ │ ├── Getters.js │ │ │ ├── Mutations.js │ │ │ ├── State.js │ │ │ └── index.js │ ├── webpack.dev.config.js │ └── webpack.prod.config.js ├── app2 │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── src │ │ ├── assets │ │ │ └── logo.png │ │ ├── components │ │ │ └── test.vue │ │ ├── main.js │ │ ├── pages │ │ │ └── App.vue │ │ ├── shims-vue.d.ts │ │ └── store │ │ │ ├── Actions.js │ │ │ ├── Getters.js │ │ │ ├── Mutations.js │ │ │ ├── State.js │ │ │ └── index.js │ ├── webpack.dev.config.js │ └── webpack.prod.config.js └── main │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── src │ ├── api │ │ └── login.js │ ├── assets │ │ ├── back.png │ │ └── logo.png │ ├── layout │ │ └── Header.vue │ ├── main.js │ ├── pages │ │ ├── App.vue │ │ ├── Home.vue │ │ └── Login.vue │ ├── router │ │ └── index.js │ ├── shims-vue.d.ts │ ├── store │ │ ├── Actions.js │ │ ├── Getters.js │ │ ├── Mutations.js │ │ ├── State.js │ │ └── index.js │ └── utils │ │ ├── index.js │ │ └── request.js │ ├── webpack.dev.config.js │ └── webpack.prod.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | package-lock.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Cody Mathisen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | # 使用 webpack5 wsrun 构建多页面应用 4 | 5 | 1.安装 yarn 6 | 2.yarn install 7 | 3.依赖暂时存放在 main 工程 其他子工程共享 8 | 4.cd packages/main yarn install 9 | 5.工程使用 vue3 vuex4 vue-router4 ant-design-vue2.x webpack5 等 10 | 11 | # 启动 12 | 13 | yarn serve / yarn start 14 | 15 | # 构建 16 | 17 | yarn build 18 | 19 | # TODO 子工程模板放到私库,创建子工程使用命令行创建 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack5-module-federation-beta", 3 | "private": true, 4 | "author": "Austion Wong", 5 | "scripts": { 6 | "build": "yarn workspaces run build", 7 | "serve": "wsrun --parallel serve", 8 | "start": "concurrently \"wsrun --parallel start\" \"wsrun --parallel serve\"" 9 | }, 10 | "workspaces": [ 11 | "packages/*" 12 | ], 13 | "devDependencies": { 14 | "concurrently": "^5.1.0", 15 | "wsrun": "^5.2.0" 16 | }, 17 | "dependencies": {} 18 | } -------------------------------------------------------------------------------- /packages/app1/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | package-lock.json -------------------------------------------------------------------------------- /packages/app1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/app1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yj-nc", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "serve": "webpack-dev-server --config webpack.dev.config.js --env.mode development --watch --profile", 9 | "build": "webpack --config webpack.prod.config.js --env.mode production" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "@babel/core": "^7.12.9", 16 | "@babel/plugin-transform-runtime": "^7.12.1", 17 | "@babel/preset-env": "^7.12.7", 18 | "@vue/compiler-sfc": "^3.0.2", 19 | "babel-loader": "^8.2.1", 20 | "babel-plugin-import": "^1.13.3", 21 | "clean-webpack-plugin": "^3.0.0", 22 | "copy-webpack-plugin": "^6.3.2", 23 | "css-loader": "^5.0.1", 24 | "html-webpack-plugin": "^4.5.0", 25 | "less": "^3.12.2", 26 | "less-loader": "^7.1.0", 27 | "mini-css-extract-plugin": "^1.3.1", 28 | "style-loader": "^2.0.0", 29 | "vue-loader": "^16.0.0-rc.1", 30 | "webpack": "^5.6.0", 31 | "webpack-cli": "^3.3.12", 32 | "webpack-dev-server": "^3.11.0" 33 | }, 34 | "dependencies": { 35 | "@babel/runtime": "^7.12.5", 36 | "ant-design-vue": "^2.0.0-beta.15", 37 | "serve": "^11.3.2", 38 | "vue": "^3.0.2", 39 | "vuex": "^4.0.0-rc.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/app1/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/120397474/webpack5-moduleFederation/0549420becefbb50820522e8b332e26b5966c3df/packages/app1/src/assets/logo.png -------------------------------------------------------------------------------- /packages/app1/src/components/test.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /packages/app1/src/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 开发模式,vue需要完整入口文件 3 | * @Author: Austin wong 4 | * @Date: 2020-11-09 00:56:37 5 | */ 6 | import { createApp } from "vue"; 7 | import box from "./pages/App.vue"; 8 | import store from './store'; 9 | import 'ant-design-vue/dist/antd.less'; 10 | 11 | const app = createApp(box); 12 | app.use(store).mount('#app'); -------------------------------------------------------------------------------- /packages/app1/src/pages/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 30 | 31 | -------------------------------------------------------------------------------- /packages/app1/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: YourName 3 | * @Date: 2021-04-16 18:13:16 4 | * @LastEditTime: 2022-07-26 22:06:12 5 | * @LastEditors: YourName 6 | * @Description: 文件功能描述 7 | * @FilePath: \yunjian-form\packages\app1\src\shims-vue.d.ts 8 | */ 9 | 10 | declare module '*.vue' { 11 | import Vue from 'vue'; 12 | export default Vue; 13 | } 14 | 15 | declare module "vue/types/vue" { 16 | interface Vue { 17 | $http: any; 18 | $Message: any; 19 | $Modal: any; 20 | } 21 | } -------------------------------------------------------------------------------- /packages/app1/src/store/Actions.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: Gouxinyu 4 | * @Date: 2020-08-03 23:25:36 5 | */ 6 | export default { 7 | 8 | } -------------------------------------------------------------------------------- /packages/app1/src/store/Getters.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: Gouxinyu 4 | * @Date: 2020-08-03 23:26:11 5 | */ 6 | export default { 7 | } -------------------------------------------------------------------------------- /packages/app1/src/store/Mutations.js: -------------------------------------------------------------------------------- 1 | const mutations = { 2 | addCount(state) { 3 | state.counter += 1; 4 | } 5 | } 6 | 7 | export default mutations; -------------------------------------------------------------------------------- /packages/app1/src/store/State.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | counter: 0 3 | } 4 | 5 | export default state; -------------------------------------------------------------------------------- /packages/app1/src/store/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: Gouxinyu 4 | * @Date: 2020-08-02 23:04:30 5 | */ 6 | 7 | import { createStore } from 'vuex'; 8 | import state from './State'; 9 | import mutations from './Mutations'; 10 | import actions from './Actions'; 11 | import getters from './Getters'; 12 | 13 | const store = createStore({ 14 | state, 15 | mutations, 16 | actions, 17 | getters 18 | }) 19 | 20 | export default store; -------------------------------------------------------------------------------- /packages/app1/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: webpack5配置 3 | * @Author: austin wong 4 | * @Date: 2020-11-09 00:27:35 5 | */ 6 | const path = require('path'); 7 | const { HotModuleReplacementPlugin, IgnorePlugin } = require('webpack'); 8 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 9 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 10 | const { VueLoaderPlugin } = require('vue-loader'); 11 | const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin"); 12 | 13 | const config = { 14 | mode: 'development', 15 | entry: './src/main.js', 16 | output: { 17 | filename: 'index.js', 18 | path: path.resolve(__dirname, 'dist') 19 | }, 20 | devServer: { 21 | contentBase: false, 22 | // publicPath: './dist', 23 | hot: true, 24 | port: 3001, 25 | open: false, 26 | // hotOnly: true, 27 | compress: true, 28 | overlay: true, 29 | disableHostCheck: true, // 新增该配置项 30 | }, 31 | watchOptions: { 32 | ignored: /node_modules/ 33 | }, 34 | plugins: [ 35 | new CleanWebpackPlugin(), 36 | new HtmlWebpackPlugin({ 37 | title: 'Hot Module Replacement', 38 | template: 'index.html' 39 | }), 40 | new IgnorePlugin(/^\.\/locale$/, /moment$/), 41 | new HotModuleReplacementPlugin(), 42 | new VueLoaderPlugin(), 43 | new ModuleFederationPlugin({ 44 | name: "app1", 45 | filename: "remoteEntry.js", 46 | remotes: { 47 | 'main': "main@http://localhost:3000/remoteEntry.js" 48 | }, 49 | exposes: { 50 | './Test': "./src/components/test.vue" 51 | }, 52 | shared: [] 53 | }) 54 | ], 55 | module: { 56 | rules: [ 57 | // babel使用runtime,避免将不需要的代码注入 58 | { 59 | test: /\.js$/, 60 | exclude: /node_modules/, 61 | use: [{ 62 | loader: 'babel-loader', 63 | options: { 64 | // cacheDirectory: true, 65 | presets: ['@babel/preset-env'], 66 | plugins: [ 67 | '@babel/plugin-transform-runtime', ['import', { 68 | "libraryName": "antd", 69 | "style": true, // or 'css' 70 | }, 'antd'] 71 | ] 72 | } 73 | }], 74 | }, 75 | { 76 | test: /\.vue$/, 77 | loader: 'vue-loader' 78 | }, 79 | { 80 | test: /\.css$/, 81 | use: ['style-loader', 'css-loader'] 82 | }, 83 | { 84 | test: /\.less$/, 85 | use: ['style-loader', 'css-loader', 86 | { 87 | loader: 'less-loader', 88 | options: { 89 | lessOptions: { 90 | modifyVars: { 91 | 'primary-color': '#4608e2', 92 | 'link-color': '#4608e2', 93 | 'border-radius-base': '20px', 94 | }, 95 | javascriptEnabled: true, 96 | } 97 | } 98 | } 99 | ], 100 | } 101 | ] 102 | }, 103 | resolve: { 104 | extensions: ['.js'] 105 | }, 106 | }; 107 | 108 | 109 | module.exports = (env) => { 110 | console.log(`当前执行${env.mode}模式`); 111 | 112 | return config; 113 | } -------------------------------------------------------------------------------- /packages/app1/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: webpack5配置 3 | * @Author: austin wong 4 | * @Date: 2021-04-16 13:26:28 5 | */ 6 | const path = require('path'); 7 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 8 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 9 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 10 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 11 | const { VueLoaderPlugin } = require('vue-loader'); 12 | const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin"); 13 | 14 | const config = { 15 | mode: 'production', 16 | entry: './src/main.js', 17 | output: { 18 | filename: 'index.js', 19 | path: path.resolve(__dirname, 'dist') 20 | }, 21 | plugins: [ 22 | new CleanWebpackPlugin(), 23 | new HtmlWebpackPlugin({ 24 | title: 'Hot Module Replacement', 25 | template: 'index.html' 26 | }), 27 | new CopyWebpackPlugin({ 28 | patterns: [ 29 | { 30 | from: 'src/assets', 31 | to: 'assets' 32 | }, 33 | ] 34 | }), 35 | new MiniCssExtractPlugin({ 36 | filename: './index.css' 37 | }), 38 | new VueLoaderPlugin(), 39 | new ModuleFederationPlugin({ 40 | name: "app1", 41 | // library: { type: "var", name: "yj-nc" }, 42 | filename: "remoteEntry.js", 43 | remotes: { 44 | 'main': "main@http://localhost:3000/remoteEntry.js" 45 | }, 46 | exposes: { 47 | './Test': "./src/components/test.vue" 48 | }, 49 | shared: [] 50 | }) 51 | ], 52 | module: { 53 | rules: [ 54 | // babel使用runtime,避免将不需要的代码注入 55 | { 56 | test: /\.js$/, 57 | exclude: /node_modules/, 58 | use: [{ 59 | loader: 'babel-loader', 60 | options: { 61 | cacheDirectory: true, 62 | presets: ['@babel/preset-env'], 63 | plugins: [ 64 | ['import', { 65 | "libraryName": "antd", 66 | "style": true, // or 'css' 67 | }, 'antd'] 68 | ] 69 | } 70 | }], 71 | }, 72 | { 73 | test: /\.vue$/, 74 | use: ['vue-loader'] 75 | }, 76 | { 77 | test: /\.css$/, 78 | use: [MiniCssExtractPlugin.loader, 'css-loader'] 79 | }, 80 | { 81 | test: /\.less$/, 82 | use: [MiniCssExtractPlugin.loader, 'css-loader', { 83 | loader: 'less-loader', 84 | options: { 85 | lessOptions: { 86 | modifyVars: { 87 | 'primary-color': '#4608e2', 88 | 'link-color': '#4608e2', 89 | 'border-radius-base': '20px', 90 | }, 91 | javascriptEnabled: true, 92 | } 93 | } 94 | }] 95 | } 96 | ] 97 | }, 98 | resolve: { 99 | extensions: ['.js'] 100 | }, 101 | }; 102 | 103 | module.exports = (env) => { 104 | console.log(`当前执行${env.mode}模式`); 105 | // 如果是开发模式, 106 | 107 | return config; 108 | } -------------------------------------------------------------------------------- /packages/app2/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | package-lock.json -------------------------------------------------------------------------------- /packages/app2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/app2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app2", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "serve": "webpack-dev-server --config webpack.dev.config.js --env.mode development --watch --profile", 9 | "build": "webpack --config webpack.prod.config.js --env.mode production" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "@babel/core": "^7.12.9", 16 | "@babel/plugin-transform-runtime": "^7.12.1", 17 | "@babel/preset-env": "^7.12.7", 18 | "@vue/compiler-sfc": "^3.0.2", 19 | "babel-loader": "^8.2.1", 20 | "babel-plugin-import": "^1.13.3", 21 | "clean-webpack-plugin": "^3.0.0", 22 | "copy-webpack-plugin": "^6.3.2", 23 | "css-loader": "^5.0.1", 24 | "html-webpack-plugin": "^4.5.0", 25 | "less": "^3.12.2", 26 | "less-loader": "^7.1.0", 27 | "mini-css-extract-plugin": "^1.3.1", 28 | "style-loader": "^2.0.0", 29 | "vue-loader": "^16.0.0-rc.1", 30 | "webpack": "^5.6.0", 31 | "webpack-cli": "^3.3.12", 32 | "webpack-dev-server": "^3.11.0" 33 | }, 34 | "dependencies": { 35 | "@babel/runtime": "^7.12.5", 36 | "ant-design-vue": "^2.0.0-beta.15", 37 | "serve": "^11.3.2", 38 | "vue": "^3.0.2", 39 | "vuex": "^4.0.0-rc.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/app2/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/120397474/webpack5-moduleFederation/0549420becefbb50820522e8b332e26b5966c3df/packages/app2/src/assets/logo.png -------------------------------------------------------------------------------- /packages/app2/src/components/test.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /packages/app2/src/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 开发模式,vue需要完整入口文件 3 | * @Author: Austin wong 4 | * @Date: 2020-11-09 00:56:37 5 | */ 6 | import { createApp } from "vue"; 7 | import box from "./pages/App.vue"; 8 | import store from './store'; 9 | import 'ant-design-vue/dist/antd.less'; 10 | 11 | const app = createApp(box); 12 | app.use(store).mount('#app'); -------------------------------------------------------------------------------- /packages/app2/src/pages/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 16 | 17 | 39 | 40 | -------------------------------------------------------------------------------- /packages/app2/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: Gouxinyu 4 | * @Date: 2020-11-13 15:34:03 5 | */ 6 | declare module '*.vue' { 7 | import Vue from 'vue'; 8 | export default Vue; 9 | } 10 | 11 | declare module "vue/types/vue" { 12 | interface Vue { 13 | $http: any; 14 | $Message: any; 15 | $Modal: any; 16 | } 17 | } -------------------------------------------------------------------------------- /packages/app2/src/store/Actions.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: Gouxinyu 4 | * @Date: 2020-08-03 23:25:36 5 | */ 6 | export default { 7 | 8 | } -------------------------------------------------------------------------------- /packages/app2/src/store/Getters.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: Gouxinyu 4 | * @Date: 2020-08-03 23:26:11 5 | */ 6 | export default { 7 | } -------------------------------------------------------------------------------- /packages/app2/src/store/Mutations.js: -------------------------------------------------------------------------------- 1 | const mutations = { 2 | addCount(state) { 3 | state.counter += 1; 4 | } 5 | } 6 | 7 | export default mutations; -------------------------------------------------------------------------------- /packages/app2/src/store/State.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | counter: 0 3 | } 4 | 5 | export default state; -------------------------------------------------------------------------------- /packages/app2/src/store/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: Gouxinyu 4 | * @Date: 2020-08-02 23:04:30 5 | */ 6 | 7 | import { createStore } from 'vuex'; 8 | import state from './State'; 9 | import mutations from './Mutations'; 10 | import actions from './Actions'; 11 | import getters from './Getters'; 12 | 13 | const store = createStore({ 14 | state, 15 | mutations, 16 | actions, 17 | getters 18 | }) 19 | 20 | export default store; -------------------------------------------------------------------------------- /packages/app2/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: webpack5配置 3 | * @Author: austin wong 4 | * @Date: 2020-11-09 00:27:35 5 | */ 6 | const path = require('path'); 7 | const { HotModuleReplacementPlugin, IgnorePlugin } = require('webpack'); 8 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 9 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 10 | const { VueLoaderPlugin } = require('vue-loader'); 11 | const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin"); 12 | 13 | const config = { 14 | mode: 'development', 15 | entry: './src/main.js', 16 | output: { 17 | filename: 'index.js', 18 | path: path.resolve(__dirname, 'dist') 19 | }, 20 | devServer: { 21 | contentBase: false, 22 | // publicPath: './dist', 23 | hot: true, 24 | port: 3002, 25 | open: false, 26 | // hotOnly: true, 27 | compress: true, 28 | overlay: true, 29 | disableHostCheck: true, // 新增该配置项 30 | }, 31 | watchOptions: { 32 | ignored: /node_modules/ 33 | }, 34 | plugins: [ 35 | new CleanWebpackPlugin(), 36 | new HtmlWebpackPlugin({ 37 | title: 'Hot Module Replacement', 38 | template: 'index.html' 39 | }), 40 | new IgnorePlugin(/^\.\/locale$/, /moment$/), 41 | new HotModuleReplacementPlugin(), 42 | new VueLoaderPlugin(), 43 | new ModuleFederationPlugin({ 44 | name: "app2", 45 | // library: { type: "var", name: "yj-nc" }, 46 | filename: "remoteEntry.js", 47 | remotes: { 48 | 'main': "main@http://localhost:3000/remoteEntry.js" 49 | }, 50 | exposes: { 51 | './APP': "./src/pages/App.vue" 52 | }, 53 | shared: [] 54 | }) 55 | ], 56 | module: { 57 | rules: [ 58 | // babel使用runtime,避免将不需要的代码注入 59 | { 60 | test: /\.js$/, 61 | exclude: /node_modules/, 62 | use: [{ 63 | loader: 'babel-loader', 64 | options: { 65 | // cacheDirectory: true, 66 | presets: ['@babel/preset-env'], 67 | plugins: [ 68 | '@babel/plugin-transform-runtime', ['import', { 69 | "libraryName": "antd", 70 | "style": true, // or 'css' 71 | }, 'antd'] 72 | ] 73 | } 74 | }], 75 | }, 76 | { 77 | test: /\.vue$/, 78 | loader: 'vue-loader' 79 | }, 80 | { 81 | test: /\.css$/, 82 | use: ['style-loader', 'css-loader'] 83 | }, 84 | { 85 | test: /\.less$/, 86 | use: ['style-loader', 'css-loader', 87 | { 88 | loader: 'less-loader', 89 | options: { 90 | lessOptions: { 91 | modifyVars: { 92 | 'primary-color': '#4608e2', 93 | 'link-color': '#4608e2', 94 | 'border-radius-base': '20px', 95 | }, 96 | javascriptEnabled: true, 97 | } 98 | } 99 | } 100 | ], 101 | } 102 | ] 103 | }, 104 | resolve: { 105 | extensions: ['.js'] 106 | }, 107 | }; 108 | 109 | 110 | module.exports = (env) => { 111 | console.log(`当前执行${env.mode}模式`); 112 | 113 | return config; 114 | } -------------------------------------------------------------------------------- /packages/app2/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: webpack5配置 3 | * @Author: austin wong 4 | * @Date: 2021-04-16 13:26:28 5 | */ 6 | const path = require('path'); 7 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 8 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 9 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 10 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 11 | const { VueLoaderPlugin } = require('vue-loader'); 12 | const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin"); 13 | 14 | const config = { 15 | mode: 'production', 16 | entry: './src/main.js', 17 | output: { 18 | filename: 'index.js', 19 | path: path.resolve(__dirname, 'dist') 20 | }, 21 | plugins: [ 22 | new CleanWebpackPlugin(), 23 | new HtmlWebpackPlugin({ 24 | title: 'Hot Module Replacement', 25 | template: 'index.html' 26 | }), 27 | new CopyWebpackPlugin({ 28 | patterns: [ 29 | { 30 | from: 'src/assets', 31 | to: 'assets' 32 | }, 33 | ] 34 | }), 35 | new MiniCssExtractPlugin({ 36 | filename: './index.css' 37 | }), 38 | new VueLoaderPlugin(), 39 | new ModuleFederationPlugin({ 40 | name: "app1", 41 | // library: { type: "var", name: "yj-nc" }, 42 | filename: "remoteEntry.js", 43 | remotes: { 44 | 'main': "main@http://localhost:3000/remoteEntry.js" 45 | }, 46 | exposes: { 47 | './Test': "./src/components/test.vue" 48 | }, 49 | shared: [] 50 | }) 51 | ], 52 | module: { 53 | rules: [ 54 | // babel使用runtime,避免将不需要的代码注入 55 | { 56 | test: /\.js$/, 57 | exclude: /node_modules/, 58 | use: [{ 59 | loader: 'babel-loader', 60 | options: { 61 | cacheDirectory: true, 62 | presets: ['@babel/preset-env'], 63 | plugins: [ 64 | ['import', { 65 | "libraryName": "antd", 66 | "style": true, // or 'css' 67 | }, 'antd'] 68 | ] 69 | } 70 | }], 71 | }, 72 | { 73 | test: /\.vue$/, 74 | use: ['vue-loader'] 75 | }, 76 | { 77 | test: /\.css$/, 78 | use: [MiniCssExtractPlugin.loader, 'css-loader'] 79 | }, 80 | { 81 | test: /\.less$/, 82 | use: [MiniCssExtractPlugin.loader, 'css-loader', { 83 | loader: 'less-loader', 84 | options: { 85 | lessOptions: { 86 | modifyVars: { 87 | 'primary-color': '#4608e2', 88 | 'link-color': '#4608e2', 89 | 'border-radius-base': '20px', 90 | }, 91 | javascriptEnabled: true, 92 | } 93 | } 94 | }] 95 | } 96 | ] 97 | }, 98 | resolve: { 99 | extensions: ['.js'] 100 | }, 101 | }; 102 | 103 | module.exports = (env) => { 104 | console.log(`当前执行${env.mode}模式`); 105 | // 如果是开发模式, 106 | 107 | return config; 108 | } -------------------------------------------------------------------------------- /packages/main/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | package-lock.json -------------------------------------------------------------------------------- /packages/main/index.html: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | webpack5 16 | 17 | 18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /packages/main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "main", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "serve": "webpack-dev-server --config webpack.dev.config.js --env.mode development --watch --profile", 9 | "build": "webpack --config webpack.prod.config.js --env.mode production" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "@babel/core": "^7.12.9", 16 | "@babel/plugin-transform-runtime": "^7.12.1", 17 | "@babel/preset-env": "^7.12.7", 18 | "@vue/compiler-sfc": "^3.0.11", 19 | "babel-loader": "^8.2.2", 20 | "babel-plugin-import": "^1.13.3", 21 | "clean-webpack-plugin": "^3.0.0", 22 | "copy-webpack-plugin": "^8.1.1", 23 | "css-loader": "^5.0.1", 24 | "file-loader": "^6.2.0", 25 | "html-webpack-plugin": "^4.5.1", 26 | "image-webpack-loader": "^7.0.1", 27 | "mini-css-extract-plugin": "^1.6.0", 28 | "sass": "^1.37.5", 29 | "sass-loader": "^11.1.1", 30 | "style-loader": "^2.0.0", 31 | "url-loader": "^4.1.1", 32 | "vue-loader": "^16.0.0-rc.1", 33 | "webpack": "^5.6.0", 34 | "webpack-cli": "^3.3.12", 35 | "webpack-dev-server": "^3.11.2", 36 | "axios": "^0.20.0" 37 | }, 38 | "dependencies": { 39 | "@babel/runtime": "^7.12.5", 40 | "ant-design-vue": "^2.1.4", 41 | "cross-env": "^7.0.3", 42 | "serve": "^11.3.2", 43 | "vue": "^3.0.11", 44 | "vue-router": "^4.0.8", 45 | "vuex": "^4.0.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/main/src/api/login.js: -------------------------------------------------------------------------------- 1 | import request from '../utils/request' 2 | const baseUrl = `http://test.yunjian613.com` 3 | 4 | // 登录 5 | export function login(data) { 6 | debugger 7 | return request({ 8 | url: baseUrl + '/java-auth/oauth/token' + data.url, 9 | method: 'post', 10 | data, 11 | }) 12 | } -------------------------------------------------------------------------------- /packages/main/src/assets/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/120397474/webpack5-moduleFederation/0549420becefbb50820522e8b332e26b5966c3df/packages/main/src/assets/back.png -------------------------------------------------------------------------------- /packages/main/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/120397474/webpack5-moduleFederation/0549420becefbb50820522e8b332e26b5966c3df/packages/main/src/assets/logo.png -------------------------------------------------------------------------------- /packages/main/src/layout/Header.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 89 | 90 | -------------------------------------------------------------------------------- /packages/main/src/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 开发模式,vue需要完整入口文件 3 | * @Author: austin wong 4 | * @Date: 2021-04-16 13:26:28 5 | */ 6 | import { createApp, defineAsyncComponent } from "vue"; 7 | import box from "./pages/App.vue"; 8 | import store from './store'; 9 | import router from './router' 10 | import Antd from 'ant-design-vue' 11 | import 'ant-design-vue/dist/antd.less'; 12 | 13 | const Content = defineAsyncComponent(() => 14 | import ('app1/Test')) 15 | 16 | const Content1 = defineAsyncComponent(() => 17 | import ('app2/APP')) 18 | 19 | const app = createApp(box); 20 | 21 | app.component('ContentElement', Content) 22 | app.component('ContentElement1', Content1) 23 | app.use(store).use(Antd).use(router).mount('#app'); -------------------------------------------------------------------------------- /packages/main/src/pages/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 13 | 15 | -------------------------------------------------------------------------------- /packages/main/src/pages/Home.vue: -------------------------------------------------------------------------------- 1 | 9 | 15 | -------------------------------------------------------------------------------- /packages/main/src/pages/Login.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 96 | 97 | -------------------------------------------------------------------------------- /packages/main/src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from "vue-router"; 2 | 3 | const routes = [{ 4 | path: "/Login", 5 | component: () => 6 | import("../pages/Login.vue") 7 | }, 8 | { 9 | path: "/", 10 | component: () => 11 | import("../pages/Home.vue") 12 | } 13 | ]; 14 | 15 | const router = createRouter({ 16 | history: createWebHistory(), 17 | routes 18 | }); 19 | 20 | export default router; -------------------------------------------------------------------------------- /packages/main/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: austin wong 4 | * @Date: 2021-04-16 13:26:28 5 | */ 6 | declare module '*.vue' { 7 | import Vue from 'vue'; 8 | export default Vue; 9 | } 10 | 11 | declare module "vue/types/vue" { 12 | interface Vue { 13 | $http: any; 14 | $Message: any; 15 | $Modal: any; 16 | } 17 | } -------------------------------------------------------------------------------- /packages/main/src/store/Actions.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: austin wong 4 | * @Date: 2021-04-16 13:26:28 5 | */ 6 | export default { 7 | 8 | } -------------------------------------------------------------------------------- /packages/main/src/store/Getters.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: austin wong 4 | * @Date: 2021-04-16 13:26:28 5 | */ 6 | export default { 7 | } -------------------------------------------------------------------------------- /packages/main/src/store/Mutations.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: austin wong 4 | * @Date: 2021-04-16 13:26:28 5 | */ 6 | export default { 7 | } -------------------------------------------------------------------------------- /packages/main/src/store/State.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: austin wong 4 | * @Date: 2021-04-16 13:26:28 5 | */ 6 | export default { 7 | } -------------------------------------------------------------------------------- /packages/main/src/store/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @description: 3 | * @Author: austin wong 4 | * @Date: 2021-04-16 13:26:28 5 | */ 6 | 7 | import { createStore } from 'vuex'; 8 | import state from './State'; 9 | import mutations from './Mutations'; 10 | import actions from './Actions'; 11 | import getters from './Getters'; 12 | 13 | const store = createStore({ 14 | // state, 15 | // mutations, 16 | // actions, 17 | // getters 18 | }) 19 | 20 | export default store; -------------------------------------------------------------------------------- /packages/main/src/utils/index.js: -------------------------------------------------------------------------------- 1 | const timestampToTime = timestamp => { 2 | let date = new Date(timestamp); //时间戳为10位需*1000,时间戳为13位的话不需乘1000 3 | let Y = date.getFullYear() + "-"; 4 | let M = 5 | (date.getMonth() + 1 < 10 6 | ? "0" + (date.getMonth() + 1) 7 | : date.getMonth() + 1) + "-"; 8 | let D = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " "; 9 | let h = 10 | (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":"; 11 | let m = 12 | (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) + 13 | ":"; 14 | let s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds(); 15 | return Y + M + D + h + m + s; 16 | }; 17 | /** 18 | * 存储localStorage 19 | */ 20 | const setStore = (name, content) => { 21 | if (!name) return; 22 | if (typeof content !== "string") { 23 | content = JSON.stringify(content); 24 | } 25 | window.localStorage.setItem(name, content); 26 | }; 27 | 28 | /** 29 | * 获取localStorage 30 | */ 31 | const getStore = name => { 32 | if (!name) return; 33 | return window.localStorage.getItem(name); 34 | }; 35 | 36 | /** 37 | * 删除localStorage 38 | */ 39 | const removeStore = name => { 40 | if (!name) return; 41 | window.localStorage.removeItem(name); 42 | }; 43 | //验证码生成 44 | const createCode = name => { 45 | let code = ""; 46 | let codeLength = 4; //验证码的长度 47 | let random = [ 48 | 0, 49 | 1, 50 | 2, 51 | 3, 52 | 4, 53 | 5, 54 | 6, 55 | 7, 56 | 8, 57 | 9, 58 | "A", 59 | "B", 60 | "C", 61 | "D", 62 | "E", 63 | "F", 64 | "G", 65 | "H", 66 | "I", 67 | "J", 68 | "K", 69 | "L", 70 | "M", 71 | "N", 72 | "O", 73 | "P", 74 | "Q", 75 | "R", 76 | "S", 77 | "T", 78 | "U", 79 | "V", 80 | "W", 81 | "X", 82 | "Y", 83 | "Z" 84 | ]; //随机数 85 | for (let i = 0; i < codeLength; i++) { 86 | //循环操作 87 | let index = Math.floor(Math.random() * 36); //取得随机数的索引(0~35) 88 | code += random[index]; //根据索引取得随机数加到code上 89 | } 90 | return code; //把code值赋给验证码 91 | }; 92 | /** 93 | * 设置cookie 94 | **/ 95 | function setCookie(name, value, day) { 96 | let date = new Date(); 97 | date.setDate(date.getDate() + day); 98 | document.cookie = name + "=" + value + ";expires=" + date; 99 | } 100 | 101 | /** 102 | * 获取cookie 103 | **/ 104 | function getCookie(name) { 105 | let reg = RegExp(name + "=([^;]+)"); 106 | let arr = document.cookie.match(reg); 107 | if (arr) { 108 | return arr[1]; 109 | } else { 110 | return ""; 111 | } 112 | } 113 | 114 | /** 115 | * 删除cookie 116 | **/ 117 | function delCookie(name) { 118 | setCookie(name, null, -1); 119 | } 120 | 121 | /** 122 | * 导出 123 | **/ 124 | export { 125 | timestampToTime, 126 | setStore, 127 | getStore, 128 | removeStore, 129 | setCookie, 130 | getCookie, 131 | delCookie, 132 | createCode 133 | }; -------------------------------------------------------------------------------- /packages/main/src/utils/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | // axios 配置 4 | axios.defaults.timeout = 1800000 5 | axios.defaults.baseURL = '' 6 | 7 | // http request 拦截器 8 | axios.interceptors.request.use( 9 | config => { 10 | const USER_TOKEN = sessionStorage.getItem('token') 11 | 12 | if (USER_TOKEN) { 13 | config.headers.common['Authorization'] = `${USER_TOKEN}` 14 | } 15 | return config 16 | }, 17 | err => { 18 | return Promise.reject(err) 19 | } 20 | ) 21 | 22 | // http response 拦截器 23 | axios.interceptors.response.use( 24 | response => { 25 | // response 里面可以判断code 如果401 就跳转登录 26 | return response 27 | }, 28 | err => { 29 | return Promise.reject(err) 30 | } 31 | ) 32 | 33 | export default axios -------------------------------------------------------------------------------- /packages/main/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { HotModuleReplacementPlugin, IgnorePlugin } = require('webpack'); 3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | const { VueLoaderPlugin } = require('vue-loader'); 6 | const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin"); 7 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 8 | const config = { 9 | mode: 'development', 10 | entry: './src/main.js', 11 | output: { 12 | filename: 'index.js', 13 | path: path.resolve(__dirname, 'dist') 14 | }, 15 | devServer: { 16 | contentBase: false, 17 | // publicPath: './dist', 18 | hot: true, 19 | port: 3000, 20 | open: true, 21 | // hotOnly: true, 22 | compress: true, 23 | overlay: true, 24 | disableHostCheck: true, // 新增该配置项 25 | proxy: { 26 | '/': { 27 | //代理api 28 | target: 'http://test.yunjian613.com', 29 | // changeOrigin: true, //是否跨域 30 | // ws: true, // proxy websockets 31 | pathRewrite: { 32 | '': '/java' 33 | } 34 | } 35 | } 36 | }, 37 | watchOptions: { 38 | ignored: /node_modules/ 39 | }, 40 | plugins: [ 41 | new CleanWebpackPlugin(), 42 | new HtmlWebpackPlugin({ 43 | title: 'Hot Module Replacement', 44 | template: 'index.html' 45 | }), 46 | new IgnorePlugin(/^\.\/locale$/, /moment$/), 47 | new HotModuleReplacementPlugin(), 48 | new VueLoaderPlugin(), 49 | new MiniCssExtractPlugin(), 50 | new ModuleFederationPlugin({ 51 | name: "main", 52 | // library: { type: "var", name: "main" }, 53 | filename: "remoteEntry.js", 54 | remotes: { 55 | 'app1': "app1@http://localhost:3001/remoteEntry.js", 56 | 'app2': "app2@http://localhost:3002/remoteEntry.js" 57 | }, 58 | exposes: {}, 59 | shared: [] 60 | }) 61 | ], 62 | module: { 63 | rules: [ 64 | // babel使用runtime,避免将不需要的代码注入 65 | { 66 | test: /\.js$/, 67 | exclude: /node_modules/, 68 | use: [{ 69 | loader: 'babel-loader', 70 | options: { 71 | // cacheDirectory: true, 72 | presets: ['@babel/preset-env'], 73 | plugins: [ 74 | '@babel/plugin-transform-runtime', ['import', { 75 | "libraryName": "antd", 76 | "style": true, // or 'css' 77 | }, 'antd'] 78 | ] 79 | } 80 | }], 81 | }, 82 | { 83 | test: /\.vue$/, 84 | loader: 'vue-loader' 85 | }, 86 | { 87 | test: /\.css$/, 88 | use: ['style-loader', 'css-loader'] 89 | }, 90 | { 91 | test: /\.scss$/, 92 | use: ["style-loader", "css-loader", "sass-loader"] 93 | }, 94 | { 95 | test: /\.less$/, 96 | use: [MiniCssExtractPlugin.loader, 'css-loader', { 97 | loader: 'less-loader', 98 | options: { 99 | lessOptions: { 100 | modifyVars: { 101 | 'primary-color': '#4608e2', 102 | 'link-color': '#4608e2', 103 | 'border-radius-base': '20px', 104 | }, 105 | javascriptEnabled: true, 106 | } 107 | } 108 | }] 109 | }, 110 | // file-laoder加载图片 111 | { 112 | test: /\.(jpg|png|jpeg|gif|svg)$/, 113 | use: ['file-loader'] 114 | } 115 | ] 116 | }, 117 | resolve: { 118 | extensions: ['.js'] 119 | }, 120 | }; 121 | 122 | 123 | module.exports = (env) => { 124 | console.log(`当前执行${env.mode}模式`); 125 | 126 | return config; 127 | } -------------------------------------------------------------------------------- /packages/main/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { HotModuleReplacementPlugin, IgnorePlugin } = require('webpack'); 3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | const { VueLoaderPlugin } = require('vue-loader'); 6 | const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin"); 7 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 8 | const config = { 9 | mode: 'development', 10 | entry: './src/main.js', 11 | output: { 12 | filename: 'index.js', 13 | path: path.resolve(__dirname, 'dist') 14 | }, 15 | devServer: { 16 | contentBase: false, 17 | // publicPath: './dist', 18 | hot: true, 19 | port: 3000, 20 | open: true, 21 | // hotOnly: true, 22 | compress: true, 23 | overlay: true, 24 | disableHostCheck: true, // 新增该配置项 25 | }, 26 | watchOptions: { 27 | ignored: /node_modules/ 28 | }, 29 | plugins: [ 30 | new CleanWebpackPlugin(), 31 | new HtmlWebpackPlugin({ 32 | title: 'Hot Module Replacement', 33 | template: 'index.html' 34 | }), 35 | new IgnorePlugin(/^\.\/locale$/, /moment$/), 36 | new HotModuleReplacementPlugin(), 37 | new VueLoaderPlugin(), 38 | new MiniCssExtractPlugin(), 39 | new ModuleFederationPlugin({ 40 | name: "main", 41 | // library: { type: "var", name: "main" }, 42 | filename: "remoteEntry.js", 43 | remotes: { 44 | 'app1': "app1@http://localhost:3001/remoteEntry.js", 45 | 'app2': "app2@http://localhost:3002/remoteEntry.js" 46 | }, 47 | exposes: {}, 48 | shared: [] 49 | }) 50 | ], 51 | module: { 52 | rules: [ 53 | // babel使用runtime,避免将不需要的代码注入 54 | { 55 | test: /\.js$/, 56 | exclude: /node_modules/, 57 | use: [{ 58 | loader: 'babel-loader', 59 | options: { 60 | // cacheDirectory: true, 61 | presets: ['@babel/preset-env'], 62 | plugins: [ 63 | '@babel/plugin-transform-runtime', ['import', { 64 | "libraryName": "antd", 65 | "style": true, // or 'css' 66 | }, 'antd'] 67 | ] 68 | } 69 | }], 70 | }, 71 | { 72 | test: /\.vue$/, 73 | loader: 'vue-loader' 74 | }, 75 | { 76 | test: /\.css$/, 77 | use: ['style-loader', 'css-loader'] 78 | }, 79 | { 80 | test: /\.scss$/, 81 | use: ["style-loader", "css-loader", "sass-loader"] 82 | }, 83 | { 84 | test: /\.less$/, 85 | use: [MiniCssExtractPlugin.loader, 'css-loader', { 86 | loader: 'less-loader', 87 | options: { 88 | lessOptions: { 89 | modifyVars: { 90 | 'primary-color': '#4608e2', 91 | 'link-color': '#4608e2', 92 | 'border-radius-base': '20px', 93 | }, 94 | javascriptEnabled: true, 95 | } 96 | } 97 | }] 98 | }, 99 | // file-laoder加载图片 100 | { 101 | test: /\.(jpg|png|jpeg|gif|svg)$/, 102 | use: ['file-loader'] 103 | } 104 | ] 105 | }, 106 | resolve: { 107 | extensions: ['.js'] 108 | }, 109 | }; 110 | 111 | 112 | module.exports = (env) => { 113 | console.log(`当前执行${env.mode}模式`); 114 | 115 | return config; 116 | } --------------------------------------------------------------------------------