something something git
This commit is contained in:
Generated
+27
-19
@@ -1415,9 +1415,9 @@
|
|||||||
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
|
||||||
},
|
},
|
||||||
"base64-js": {
|
"base64-js": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||||
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
|
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"base64id": {
|
"base64id": {
|
||||||
@@ -7215,12 +7215,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
"integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==",
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "~5.1.0"
|
"safe-buffer": "~5.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10554,9 +10562,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-4.1.4.tgz",
|
||||||
"integrity": "sha512-jvNoEQSPXJdssFwqPSgWjsOrb+ELoE+ILpHPKXC83tIxOlh2U75F1KuB2luLD/3a6/7K3Vw5pDn+hvu0C4AzSw==",
|
"integrity": "sha512-+ZwXJvdSwbd60jG0Illav0F06GDJF0R4ydZ21Q3wGAFKoBGyJGo34F63vzJHgvYxc1ukOtIjvwEvl9MkjzM6Pg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
@@ -10667,9 +10675,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"timers-browserify": {
|
"timers-browserify": {
|
||||||
"version": "2.0.10",
|
"version": "2.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz",
|
||||||
"integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==",
|
"integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"setimmediate": "^1.0.4"
|
"setimmediate": "^1.0.4"
|
||||||
@@ -11383,9 +11391,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"webpack": {
|
"webpack": {
|
||||||
"version": "4.39.1",
|
"version": "4.39.2",
|
||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.1.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.2.tgz",
|
||||||
"integrity": "sha512-/LAb2TJ2z+eVwisldp3dqTEoNhzp/TLCZlmZm3GGGAlnfIWDgOEE758j/9atklNLfRyhKbZTCOIoPqLJXeBLbQ==",
|
"integrity": "sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@webassemblyjs/ast": "1.8.5",
|
"@webassemblyjs/ast": "1.8.5",
|
||||||
@@ -11414,9 +11422,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": {
|
"acorn": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz",
|
||||||
"integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==",
|
"integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -12,7 +12,7 @@
|
|||||||
"build-widget": "rollup -c src/frontend/widget/rollup.config.js; mkdir -p plugins/PluginManager; cp FrontendPlugin.js plugins/PluginManager",
|
"build-widget": "rollup -c src/frontend/widget/rollup.config.js; mkdir -p plugins/PluginManager; cp FrontendPlugin.js plugins/PluginManager",
|
||||||
"clean": "rm -rf lib static plugins data conf dist widget .rpt2_cache *.js *.ts src/frontend/dashboard/dist",
|
"clean": "rm -rf lib static plugins data conf dist widget .rpt2_cache *.js *.ts src/frontend/dashboard/dist",
|
||||||
"update-frontblock": "rm -rf node_modules/frontblock*; npm install",
|
"update-frontblock": "rm -rf node_modules/frontblock*; npm install",
|
||||||
"webpack": "webpack --mode production --entry ./dist/FrontblockLib.js --output ./dist/FrontblockLib.js"
|
"webpack": "webpack --config src/backend/webpack.prod.js --progress --colors"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
"rollup-plugin-typescript2": "^0.10.0",
|
"rollup-plugin-typescript2": "^0.10.0",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"style-loader": "^0.23.1",
|
"style-loader": "^0.23.1",
|
||||||
"terser-webpack-plugin": "^1.3.0",
|
"terser-webpack-plugin": "^1.4.1",
|
||||||
"ts-jest": "^24.0.2",
|
"ts-jest": "^24.0.2",
|
||||||
"ts-loader": "^5.3.3",
|
"ts-loader": "^5.3.3",
|
||||||
"tslint": "^5.18.0",
|
"tslint": "^5.18.0",
|
||||||
@@ -98,10 +98,10 @@
|
|||||||
"typescript-declaration-webpack-plugin": "^0.1.1",
|
"typescript-declaration-webpack-plugin": "^0.1.1",
|
||||||
"uglifyjs-webpack-plugin": "^2.1.3",
|
"uglifyjs-webpack-plugin": "^2.1.3",
|
||||||
"url-loader": "^1.1.2",
|
"url-loader": "^1.1.2",
|
||||||
"webpack": "^4.35.2",
|
"webpack": "^4.39.2",
|
||||||
"webpack-cli": "^3.3.5"
|
"webpack-cli": "^3.3.5"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"lib/**/*"
|
"lib/**/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+121
-28
@@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
import * as Logger from 'log4js'
|
import * as Logger from 'log4js'
|
||||||
import { socketioRPC, ConfigLoader } from 'frontblock-generic/Plugin';
|
import { socketioRPC, ConfigLoader, Plugin } from 'frontblock-generic/Plugin';
|
||||||
import { ErrorResponse, SuccessResponse } from 'frontblock-generic/Types';
|
import { ErrorResponse, SuccessResponse } from 'frontblock-generic/Types';
|
||||||
import express = require('express');
|
import express = require('express');
|
||||||
import http = require('http');
|
import http = require('http');
|
||||||
import bsock = require('bsock');
|
import bsock = require('bsock');
|
||||||
import { FrontblockCherryPicker } from "git-cherrypicker"
|
import { FrontblockCherryPicker } from "git-cherrypicker"
|
||||||
import { promises as fs } from "fs"
|
import { promises as fs } from "fs"
|
||||||
import { GitUpdater } from "./GitUpdater";
|
import { GitUpdater, RepoFolderStatus, } from "./GitUpdater";
|
||||||
import * as git from "simple-git/promise"
|
import * as path from "path"
|
||||||
|
|
||||||
const kfs = require("key-file-storage").default('kfs')
|
const kfs = require("key-file-storage").default('kfs')
|
||||||
|
|
||||||
@@ -70,7 +70,12 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
|||||||
private httpServer
|
private httpServer
|
||||||
private io = bsock.createServer()
|
private io = bsock.createServer()
|
||||||
private wsServer = http.createServer()
|
private wsServer = http.createServer()
|
||||||
private pm
|
|
||||||
|
private dashboardUpdater:GitUpdater
|
||||||
|
private adminUpdater:GitUpdater
|
||||||
|
private pluginUpdaters:{[name in string]:GitUpdater} = {}
|
||||||
|
private loadedPlugins:{[name in string]:Plugin} = {}
|
||||||
|
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super("FrontblockAdmin")
|
super("FrontblockAdmin")
|
||||||
@@ -83,29 +88,82 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async updateFrontblockLib(){
|
private async updateFrontblockLib(){
|
||||||
|
logger.warn("Picking FrontblockLib...")
|
||||||
await (new FrontblockCherryPicker("fb-dist/admin", "master", "FrontblockLib.js")).write("./static/FrontblockLib.js")
|
await (new FrontblockCherryPicker("fb-dist/admin", "master", "FrontblockLib.js")).write("./static/FrontblockLib.js")
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateDashboard(){
|
private async updateDashboard():Promise<RepoFolderStatus>{
|
||||||
const dashboard = new GitUpdater("./static")
|
logger.warn("Cloning dashboard...")
|
||||||
const status = await dashboard.cloneRepo("https://gitea.frontblock.me/fb-dist/dashboard.git", true)
|
this.dashboardUpdater = new GitUpdater("./static")
|
||||||
console.log(status)
|
const status = await this.dashboardUpdater.cloneRepo("https://gitea.frontblock.me/fb-dist/dashboard.git", true)
|
||||||
|
return(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updatePluginmanager(){
|
private async installPlugin(name: string):Promise<RepoFolderStatus>{
|
||||||
const dashboard = new GitUpdater("./plugins/PluginManager")
|
logger.warn("Cloning "+name+"...")
|
||||||
const status = await dashboard.cloneRepo("https://gitea.frontblock.me/fb-dist/pluginmanager.git", true)
|
this.pluginUpdaters[name] = new GitUpdater("./plugins/"+name)
|
||||||
console.log(status)
|
const status = await this.pluginUpdaters[name].cloneRepo("https://gitea.frontblock.me/fb-dist/"+name.toLowerCase()+".git", true)
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
private async startPlugin(name:string):Promise<boolean>{
|
||||||
|
if(!this.pluginUpdaters[name]) return false
|
||||||
|
const status = await this.pluginUpdaters[name].getStatus()
|
||||||
|
if(!status.exists || status.empty || !status.tags || status.tags.length === 0){
|
||||||
|
logger.error("Bad repo status", name, status)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.loadedPlugins[name]){
|
||||||
|
logger.error("Plugin", name, "is already started")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let str = "../plugins/"+name+"/Plugin"
|
||||||
|
const pluginClass = await import(str)
|
||||||
|
const pluginObj = new pluginClass.default()
|
||||||
|
await pluginObj.start()
|
||||||
|
this.loadedPlugins[name] = pluginObj
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updatePlugin(name:string):Promise<boolean>{
|
||||||
|
if(!this.pluginUpdaters[name]) return false
|
||||||
|
const status = await this.pluginUpdaters[name].getStatus()
|
||||||
|
if(!status.exists || status.empty || !status.tags || status.tags.length === 0){
|
||||||
|
logger.error("Bad repo status", name, status)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if(status.currentTag == status.latestTag){
|
||||||
|
logger.warn(name, "already at latest tag")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.loadedPlugins[name]){
|
||||||
|
logger.error("Plugin", name, "is running. Stop it first")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pluginUpdaters[name].checkoutTag(status.latestTag!)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private async setPluginVersion(pluginName:string, tag:string):Promise<RepoFolderStatus>{
|
||||||
|
const status = await this.pluginUpdaters[pluginName].getStatus()
|
||||||
|
if(!status.exists || !status.tags || status.tags.length === 0 || !status.tags.includes(tag)){
|
||||||
|
logger.error("Bad repo status", pluginName, status)
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.pluginUpdaters[pluginName].checkoutTag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async initialize(){
|
private async initialize(){
|
||||||
await this.updateDashboard()
|
await this.updateDashboard()
|
||||||
await this.updateFrontblockLib()
|
await this.updateFrontblockLib()
|
||||||
await this.updatePluginmanager()
|
await this.installPlugin("PluginManager")
|
||||||
|
//await this.updatePluginmanager()
|
||||||
let str = "../plugins/PluginManager/Plugin"
|
|
||||||
const PM = await import(str)
|
|
||||||
this.pm = new PM.default()
|
|
||||||
|
|
||||||
this.startWebsocket()
|
this.startWebsocket()
|
||||||
this.startWebserver()
|
this.startWebserver()
|
||||||
@@ -132,20 +190,55 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
|||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
owner: 'Admin',
|
owner: 'Admin',
|
||||||
name: 'installPluginManager',
|
name: 'installPlugin',
|
||||||
|
args: 'name',
|
||||||
|
info: {
|
||||||
|
type: 'call',
|
||||||
|
fn: async (name:string) => {
|
||||||
|
return await this.installPlugin(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
owner: 'Admin',
|
||||||
|
name: 'startPlugin',
|
||||||
|
args: 'name',
|
||||||
|
info: {
|
||||||
|
type: 'call',
|
||||||
|
fn: async (name:string) => {
|
||||||
|
return await this.startPlugin(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
owner: 'PluginManager',
|
||||||
|
name: 'getLoadedPluginNames',
|
||||||
args: '',
|
args: '',
|
||||||
info: {
|
info: {
|
||||||
type: 'call',
|
type: 'call',
|
||||||
fn: () => {}
|
fn: () => Object.keys(this.loadedPlugins)
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
owner: 'Admin',
|
||||||
|
name: 'updatePlugin',
|
||||||
|
args: 'name',
|
||||||
|
info: {
|
||||||
|
type: 'call',
|
||||||
|
fn: async (name) => {return await this.updatePlugin(name)}
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
owner: 'Admin',
|
||||||
|
name: 'setPluginVersion',
|
||||||
|
args: 'name, tag',
|
||||||
|
info: {
|
||||||
|
type: 'call',
|
||||||
|
fn: async (name, tag) => {return await this.setPluginVersion(name, tag)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
//translate RPCs to socket-bound function metadata
|
//translate RPCs to socket-bound function metadata
|
||||||
const loadedPlugins = this.pm.getLoadedPlugins()
|
const loadedPlugins = this.loadedPlugins
|
||||||
for(const name in loadedPlugins){
|
for(const name in loadedPlugins){
|
||||||
loadedPlugins[name].backend.exportRPCs().forEach(rpc => {
|
loadedPlugins[name].exportRPCs().forEach(rpc => {
|
||||||
const info = this.rpcToRpcInfo(name, rpc)
|
const info = this.rpcToRpcInfo(name, rpc)
|
||||||
rpcInfos.push(info)
|
rpcInfos.push(info)
|
||||||
})
|
})
|
||||||
@@ -207,10 +300,6 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private installPluginManager(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private startWebserver(){
|
private startWebserver(){
|
||||||
if(this.httpServer != null || this.express != null){
|
if(this.httpServer != null || this.express != null){
|
||||||
@@ -225,8 +314,12 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
|||||||
/**
|
/**
|
||||||
* get the compiled FrontendPlugins.js
|
* get the compiled FrontendPlugins.js
|
||||||
*/
|
*/
|
||||||
this.express.get('/plugins/:id'+".js", (request, response) => {
|
this.express.get('/plugins/:id'+".js", async (request, response) => {
|
||||||
let frontend = this.pm.getFrontend(request.params.id)
|
const pth = path.resolve("plugins/"+request.params.id, "FrontendPlugin.js");
|
||||||
|
logger.info("Loading frontend plugin from fs", pth)
|
||||||
|
const file = await fs.readFile(pth)
|
||||||
|
const frontend = file.toString()
|
||||||
|
|
||||||
response.status(200)
|
response.status(200)
|
||||||
response.set('Content-Type', 'application/javascript')
|
response.set('Content-Type', 'application/javascript')
|
||||||
response.send(frontend)
|
response.send(frontend)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const rmrf = (path:string, options = {}) => {
|
|||||||
return new Promise((acc, _) => rimraf(path, options, acc))
|
return new Promise((acc, _) => rimraf(path, options, acc))
|
||||||
}
|
}
|
||||||
|
|
||||||
type RepoFolderStatus = {
|
export type RepoFolderStatus = {
|
||||||
exists: boolean
|
exists: boolean
|
||||||
empty: boolean
|
empty: boolean
|
||||||
currentTag?: string
|
currentTag?: string
|
||||||
@@ -53,6 +53,8 @@ export class GitUpdater{
|
|||||||
}
|
}
|
||||||
|
|
||||||
async cloneRepo(from:string, force:boolean = false):Promise<RepoFolderStatus> {
|
async cloneRepo(from:string, force:boolean = false):Promise<RepoFolderStatus> {
|
||||||
|
if(this.folderPath === "." && force)
|
||||||
|
throw new Error("refusing to `rm -rf .`: \ncloneRepo(from: "+from+", force: "+force+")")
|
||||||
if(force){
|
if(force){
|
||||||
await rmrf(this.folderPath)
|
await rmrf(this.folderPath)
|
||||||
await fs.mkdir(this.folderPath, { recursive: true });
|
await fs.mkdir(this.folderPath, { recursive: true });
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
optimization: {
|
||||||
|
minimize: false
|
||||||
|
},
|
||||||
|
mode: 'production',
|
||||||
|
target: "node",
|
||||||
|
|
||||||
|
entry: path.resolve(__dirname, '../../dist/FrontblockLib.js'),
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, '../../dist'),
|
||||||
|
filename: 'FrontblockLib.js',
|
||||||
|
libraryTarget: 'commonjs',
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
minimizer: [new TerserPlugin({
|
||||||
|
cache: true,
|
||||||
|
parallel: true,
|
||||||
|
terserOptions:{
|
||||||
|
mangle: false,
|
||||||
|
keep_classnames: true
|
||||||
|
}
|
||||||
|
})],
|
||||||
|
splitChunks: {
|
||||||
|
cacheGroups: {
|
||||||
|
common: {
|
||||||
|
chunks: 'all',
|
||||||
|
minChunks: 2,
|
||||||
|
maxInitialRequests: 5,
|
||||||
|
minSize: 0,
|
||||||
|
name: 'common'
|
||||||
|
},
|
||||||
|
vendor: {
|
||||||
|
test: /node_modules/,
|
||||||
|
chunks: 'all',
|
||||||
|
name: 'vendor',
|
||||||
|
priority: 10,
|
||||||
|
enforce: true,
|
||||||
|
minChunks: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user