mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
refactoring, split webpack configs + get rid of electron-webpack
This commit is contained in:
parent
a4d66fffda
commit
9aa815bc14
4
.babelrc
4
.babelrc
@ -1,8 +1,6 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env", {"modules": "commonjs"}
|
||||
],
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react",
|
||||
"@lingui/babel-preset-react"
|
||||
],
|
||||
|
||||
41
package.json
41
package.json
@ -5,10 +5,13 @@
|
||||
"version": "3.5.0-beta.1",
|
||||
"main": "src/main",
|
||||
"scripts": {
|
||||
"dev": "DEBUG=true electron-webpack dev",
|
||||
"compile": "yarn download-bins && yarn i18n:compile && electron-webpack compile",
|
||||
"compile:main": "electron-webpack main",
|
||||
"compile:renderer": "electron-webpack renderer",
|
||||
"dev": "DEBUG=true concurrently yarn:dev:*",
|
||||
"dev:main": "webpack-cli --watch --cache --config webpack.main.ts",
|
||||
"dev:render": "webpack-cli --watch --cache --config webpack.renderer.ts",
|
||||
"compile": "concurrently 'yarn download-bins' 'yarn i18n:compile' 'yarn make-dll' && concurrently yarn:compile:*",
|
||||
"compile:main": "webpack -p --progress --config webpack.main.ts",
|
||||
"compile:renderer": "webpack -p --progress --config webpack.renderer.ts",
|
||||
"make-dll": "webpack --config webpack.dll.ts",
|
||||
"build:linux": "yarn compile && electron-builder --linux --dir -c.productName=LensDev",
|
||||
"build:mac": "yarn compile && electron-builder --mac --dir -c.productName=LensDev",
|
||||
"build:win": "yarn compile && electron-builder --win --dir -c.productName=LensDev",
|
||||
@ -17,7 +20,7 @@
|
||||
"dist": "yarn compile && electron-builder -p onTag",
|
||||
"dist:win": "yarn compile && electron-builder -p onTag --x64 --ia32",
|
||||
"dist:dir": "yarn dist --dir -c.compression=store -c.mac.identity=null",
|
||||
"postinstall": "concurrently patch-package",
|
||||
"postinstall": "patch-package && concurrently 'electron-builder install-app-deps' 'yarn make-dll'",
|
||||
"i18n:extract": "lingui extract",
|
||||
"i18n:compile": "lingui compile",
|
||||
"download-bins": "concurrently yarn:download:*",
|
||||
@ -34,18 +37,6 @@
|
||||
"engines": {
|
||||
"node": ">=12.0 <13.0"
|
||||
},
|
||||
"electronWebpack": {
|
||||
"commonSourceDirectory": "./src/common",
|
||||
"staticSourceDirectory": "./static",
|
||||
"main": {
|
||||
"sourceDirectory": "./src/main"
|
||||
},
|
||||
"renderer": {
|
||||
"sourceDirectory": "./src/renderer",
|
||||
"template": "./src/renderer/template.html",
|
||||
"webpackConfig": "./src/renderer/webpack.renderer.js"
|
||||
}
|
||||
},
|
||||
"lingui": {
|
||||
"locales": [
|
||||
"en",
|
||||
@ -56,11 +47,6 @@
|
||||
"sourceLocale": "en",
|
||||
"fallbackLocale": "en",
|
||||
"compileNamespace": "cjs",
|
||||
"extractBabelOptions": {
|
||||
"plugins": [
|
||||
"@babel/plugin-syntax-dynamic-import"
|
||||
]
|
||||
},
|
||||
"catalogs": [
|
||||
{
|
||||
"path": "./locales/{locale}/messages",
|
||||
@ -225,9 +211,11 @@
|
||||
"@types/dompurify": "^2.0.2",
|
||||
"@types/hapi": "^18.0.3",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/html-webpack-plugin": "^3.2.3",
|
||||
"@types/jest": "^25.2.3",
|
||||
"@types/material-ui": "^0.21.7",
|
||||
"@types/md5-file": "^4.0.2",
|
||||
"@types/mini-css-extract-plugin": "^0.9.1",
|
||||
"@types/react": "^16.9.35",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
@ -239,6 +227,7 @@
|
||||
"@types/shelljs": "^0.8.8",
|
||||
"@types/tcp-port-used": "^1.0.0",
|
||||
"@types/tempy": "^0.3.0",
|
||||
"@types/terser-webpack-plugin": "^3.0.0",
|
||||
"@types/universal-analytics": "^0.4.4",
|
||||
"@types/uuid": "^8.0.0",
|
||||
"@types/webdriverio": "^4.13.0",
|
||||
@ -247,6 +236,7 @@
|
||||
"ace-builds": "^1.4.11",
|
||||
"ansi_up": "^4.0.4",
|
||||
"babel-core": "^7.0.0-beta.3",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-plugin-macros": "^2.8.0",
|
||||
"bootstrap": "^4.5.0",
|
||||
"bootstrap-vue": "^2.15.0",
|
||||
@ -257,17 +247,17 @@
|
||||
"dompurify": "^2.0.11",
|
||||
"electron-builder": "^22.7.0",
|
||||
"electron-notarize": "^0.3.0",
|
||||
"electron-webpack": "^2.8.2",
|
||||
"electron-webpack-ts": "^4.0.1",
|
||||
"file-loader": "^6.0.0",
|
||||
"flex.box": "^3.4.4",
|
||||
"hashicon": "^0.3.0",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"include-media": "^1.4.9",
|
||||
"jest": "^26.0.1",
|
||||
"make-plural": "^6.2.1",
|
||||
"material-design-icons": "^3.0.1",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"mobx": "^5.15.4",
|
||||
"mobx-observable-history": "^1.0.3",
|
||||
"mobx-react": "^6.2.2",
|
||||
@ -285,8 +275,8 @@
|
||||
"react-select": "^3.1.0",
|
||||
"react-window": "^1.8.5",
|
||||
"sass-loader": "^8.0.2",
|
||||
"source-map-support": "^0.5.19",
|
||||
"spectron": "^8.0.0",
|
||||
"terser-webpack-plugin": "^3.0.3",
|
||||
"ts-jest": "^26.1.0",
|
||||
"ts-loader": "^7.0.5",
|
||||
"ts-node": "^8.10.2",
|
||||
@ -303,7 +293,6 @@
|
||||
"vuex": "^3.4.0",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"xterm": "^4.6.0",
|
||||
"xterm-addon-fit": "^0.4.0"
|
||||
}
|
||||
|
||||
25
src/common/register-static.ts
Normal file
25
src/common/register-static.ts
Normal file
@ -0,0 +1,25 @@
|
||||
// Setup static folder for common assets
|
||||
|
||||
import path from "path";
|
||||
import { protocol } from "electron"
|
||||
import logger from "../main/logger";
|
||||
import { staticDir, staticProto } from "./vars";
|
||||
|
||||
export function registerStaticProtocol(rootFolder = staticDir) {
|
||||
const scheme = staticProto.replace("://", "");
|
||||
protocol.registerFileProtocol(scheme, (request, callback) => {
|
||||
const relativePath = request.url.replace(staticProto, "");
|
||||
const absPath = path.resolve(rootFolder, relativePath);
|
||||
callback(absPath);
|
||||
}, (error) => {
|
||||
logger.debug(`Failed to register protocol "${scheme}"`, error);
|
||||
})
|
||||
}
|
||||
|
||||
export function getStaticUrl(filePath: string) {
|
||||
return staticProto + filePath;
|
||||
}
|
||||
|
||||
export function getStaticPath(filePath: string) {
|
||||
return path.resolve(staticDir, filePath);
|
||||
}
|
||||
@ -1,19 +1,21 @@
|
||||
// App's common paths/flags/etc. for any process
|
||||
import packageInfo from "../../package.json"
|
||||
// App's common configuration for any process (main, renderer, build pipeline, etc.)
|
||||
import path from "path";
|
||||
|
||||
const { main, renderer } = packageInfo.electronWebpack;
|
||||
|
||||
export const outDir = path.resolve(__dirname, "../dist");
|
||||
export const mainDir = path.resolve(__dirname, "../", main.sourceDirectory);
|
||||
export const rendererDir = path.resolve(__dirname, "../", renderer.sourceDirectory);
|
||||
|
||||
export const isMac = process.platform === "darwin"
|
||||
export const isWindows = process.platform === "win32"
|
||||
export const isProduction = process.env.NODE_ENV === "production"
|
||||
export const isDevelopment = !isProduction;
|
||||
export const buildVersion = process.env.BUILD_VERSION;
|
||||
|
||||
// Paths
|
||||
export const staticDir = path.resolve(__dirname, "../../static");
|
||||
export const outDir = path.resolve(__dirname, "../../dist");
|
||||
export const mainDir = path.resolve(__dirname, "../main");
|
||||
export const rendererDir = path.resolve(__dirname, "../renderer");
|
||||
|
||||
// Apis
|
||||
export const staticProto = "static://"
|
||||
|
||||
export const apiPrefix = {
|
||||
BASE: '/api',
|
||||
TERMINAL: '/api-terminal', // terminal api
|
||||
|
||||
@ -18,6 +18,7 @@ import { shellSync } from "./shell-sync"
|
||||
import { getFreePort } from "./port"
|
||||
import { mangleProxyEnv } from "./proxy-env"
|
||||
import { findMainWebContents } from "./webcontents"
|
||||
import { registerStaticProtocol } from "../common/register-static";
|
||||
import { isDevelopment, isMac } from "../common/vars";
|
||||
|
||||
mangleProxyEnv()
|
||||
@ -41,12 +42,15 @@ async function main() {
|
||||
updater.start();
|
||||
|
||||
tracker.event("app", "start");
|
||||
|
||||
registerStaticProtocol();
|
||||
protocol.registerFileProtocol('store', (request, callback) => {
|
||||
const url = request.url.substr(8)
|
||||
callback(path.normalize(`${app.getPath("userData")}/${url}`))
|
||||
}, (error) => {
|
||||
if (error) console.error('Failed to register protocol')
|
||||
})
|
||||
|
||||
let port: number = null
|
||||
// find free port
|
||||
try {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import http from "http"
|
||||
import path from "path"
|
||||
import { readFile } from "fs"
|
||||
import { Cluster } from "./cluster"
|
||||
import { configRoute } from "./routes/config"
|
||||
import { helmApi } from "./helm-api"
|
||||
@ -8,7 +9,7 @@ import { kubeconfigRoute } from "./routes/kubeconfig"
|
||||
import { metricsRoute } from "./routes/metrics"
|
||||
import { watchRoute } from "./routes/watch"
|
||||
import { portForwardRoute } from "./routes/port-forward"
|
||||
import { readFile } from "fs"
|
||||
import { getStaticPath } from "../common/register-static";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const Call = require('@hapi/call');
|
||||
@ -84,8 +85,8 @@ export class Router {
|
||||
return request
|
||||
}
|
||||
|
||||
protected handleStaticFile(file: string, response: http.ServerResponse) {
|
||||
const asset = path.join(__static, file)
|
||||
protected handleStaticFile(filePath: string, response: http.ServerResponse) {
|
||||
const asset = getStaticPath(filePath);
|
||||
readFile(asset, (err, data) => {
|
||||
if (err) {
|
||||
// default to index.html so that react routes work when page is refreshed
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import path from "path"
|
||||
import { BrowserWindow, shell } from "electron"
|
||||
import { PromiseIpc } from "electron-promise-ipc"
|
||||
import windowStateKeeper from "electron-window-state"
|
||||
import { tracker } from "./tracker";
|
||||
import { isDevelopment } from "../common/vars";
|
||||
import { getStaticUrl } from "../common/register-static";
|
||||
|
||||
export class WindowManager {
|
||||
public mainWindow: BrowserWindow = null;
|
||||
@ -32,7 +32,7 @@ export class WindowManager {
|
||||
}
|
||||
})
|
||||
if (showSplash) {
|
||||
this.splashWindow.loadFile(path.join(__static, "/splash.html"))
|
||||
this.splashWindow.loadFile(getStaticUrl("splash.html"))
|
||||
this.splashWindow.show()
|
||||
}
|
||||
|
||||
|
||||
@ -28,16 +28,17 @@
|
||||
|
||||
<script>
|
||||
import marked from 'marked'
|
||||
import fs from 'fs'
|
||||
import path from "path"
|
||||
import {readFileSync} from 'fs'
|
||||
import { getStaticPath } from "../../../common/register-static"
|
||||
|
||||
export default {
|
||||
name: 'WhatsNewPage',
|
||||
data() {
|
||||
let releaseNotes = getStaticPath("RELEASE_NOTES.md");
|
||||
let content = marked(readFileSync(releaseNotes, 'utf8'));
|
||||
return {
|
||||
error: "",
|
||||
// eslint-disable-next-line
|
||||
content: marked(fs.readFileSync(path.join(__static, "RELEASE_NOTES.md"), 'utf8')),
|
||||
content: content,
|
||||
}
|
||||
},
|
||||
components: {},
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
// Renderer process
|
||||
|
||||
import "../common/system-ca"
|
||||
import { App } from "./components/app";
|
||||
// import { App } from "./components/app";
|
||||
// import { appInitVue } from "./_vue";
|
||||
// appInitVue()
|
||||
// App.init();
|
||||
|
||||
App.init();
|
||||
var app = document.getElementById("app")
|
||||
app.innerHTML = "RUNNING!!"
|
||||
|
||||
@ -3,8 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Lens - The Kubernetes IDE</title>
|
||||
<!-- <meta name="viewport" content="width=device-width, initial-scale=1">-->
|
||||
<!-- <meta http-equiv="Content-Security-Policy" content="script-src 'self'">-->
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@ -1,46 +0,0 @@
|
||||
// fixme: convert to typescript (support webpack types, reuse vars.ts)
|
||||
const path = require("path");
|
||||
|
||||
module.exports = function (config, env) {
|
||||
const {module} = config;
|
||||
const {rules} = module;
|
||||
|
||||
// localization support
|
||||
// https://lingui.js.org/guides/typescript.html
|
||||
patchLoader(".tsx", "ts-loader", loader => {
|
||||
loader.options = Object.assign({}, loader.options, {
|
||||
compilerOptions: {
|
||||
jsx: "preserve", // @lingui/babel-preset-react
|
||||
target: "es2016", // @lingui/babel-preset-react
|
||||
}
|
||||
})
|
||||
return ["babel-loader", loader]
|
||||
});
|
||||
|
||||
// sass common vars file import
|
||||
patchLoader(".scss", "sass-loader", loader => {
|
||||
loader.options = Object.assign({}, loader.options, {
|
||||
prependData: '@import "vars.scss";',
|
||||
sassOptions: {
|
||||
includePaths: [
|
||||
path.resolve(__dirname, "components")
|
||||
]
|
||||
}
|
||||
})
|
||||
return loader;
|
||||
});
|
||||
|
||||
function patchLoader(fileType, loaderName, updater) {
|
||||
let rule = rules.find(rule => fileType.match(rule.test));
|
||||
if (rule) {
|
||||
let loaders = [rule.use].flat();
|
||||
let index = loaders.findIndex(loader => loader === loaderName || loader.loader === loaderName);
|
||||
let loader = typeof loaders[index] === "string" ? {loader: loaders[index]} : loaders[index];
|
||||
loaders[index] = updater(loader);
|
||||
rule.use = loaders.flat();
|
||||
console.info(`Patched webpack's renderer config for "${loaderName}" in ${__filename}`, loader);
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
@ -1,14 +1,13 @@
|
||||
{
|
||||
"extends": "./node_modules/electron-webpack/tsconfig-base.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "./dist",
|
||||
"jsx": "react",
|
||||
"target": "ES2017",
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"module": "CommonJS",
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"moduleResolution": "Node",
|
||||
"sourceMap": true,
|
||||
"sourceMap": false,
|
||||
"strict": false,
|
||||
"noImplicitAny": true,
|
||||
"noUnusedLocals": false,
|
||||
@ -28,10 +27,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"types/*"
|
||||
],
|
||||
"ts-node": {
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS"
|
||||
|
||||
5
types/globals.d.ts
vendored
5
types/globals.d.ts
vendored
@ -1,5 +0,0 @@
|
||||
export {}
|
||||
|
||||
declare global {
|
||||
const __static: string; // https://webpack.electron.build/using-static-assets
|
||||
}
|
||||
0
types/modules.d.ts → types/mocks.d.ts
vendored
0
types/modules.d.ts → types/mocks.d.ts
vendored
32
webpack.dll.ts
Executable file
32
webpack.dll.ts
Executable file
@ -0,0 +1,32 @@
|
||||
import path from "path";
|
||||
import webpack from "webpack";
|
||||
import { isDevelopment, outDir } from "./src/common/vars";
|
||||
|
||||
export const libName = "dll"
|
||||
export const manifestPath = path.resolve(outDir, `${libName}.manifest.json`);
|
||||
|
||||
export const externalPackages = [
|
||||
"react", "react-dom",
|
||||
"ace-builds", "xterm",
|
||||
"moment",
|
||||
];
|
||||
|
||||
export default function (): webpack.Configuration {
|
||||
return {
|
||||
mode: isDevelopment ? "development" : "production",
|
||||
cache: isDevelopment,
|
||||
entry: {
|
||||
[libName]: externalPackages
|
||||
},
|
||||
output: {
|
||||
library: libName,
|
||||
libraryTarget: "commonjs"
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DllPlugin({
|
||||
name: libName,
|
||||
path: manifestPath,
|
||||
})
|
||||
],
|
||||
}
|
||||
}
|
||||
37
webpack.main.ts
Executable file
37
webpack.main.ts
Executable file
@ -0,0 +1,37 @@
|
||||
import path from "path";
|
||||
import webpack from "webpack";
|
||||
import { isProduction, mainDir, outDir } from "./src/common/vars";
|
||||
|
||||
export default function (): webpack.Configuration {
|
||||
return {
|
||||
target: "electron-main",
|
||||
mode: isProduction ? "production" : "development",
|
||||
entry: {
|
||||
main: path.resolve(mainDir, "index.ts"),
|
||||
},
|
||||
output: {
|
||||
path: outDir,
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.json', '.js', '.ts']
|
||||
},
|
||||
externals: [
|
||||
"@kubernetes/client-node",
|
||||
"handlebars",
|
||||
"node-pty",
|
||||
"ws",
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.node$/,
|
||||
use: "node-loader"
|
||||
},
|
||||
{
|
||||
test: /\.ts?$/,
|
||||
use: "ts-loader",
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
}
|
||||
134
webpack.renderer.ts
Executable file
134
webpack.renderer.ts
Executable file
@ -0,0 +1,134 @@
|
||||
import path from "path";
|
||||
import webpack from "webpack";
|
||||
import HtmlWebpackPlugin from "html-webpack-plugin";
|
||||
import MiniCssExtractPlugin from "mini-css-extract-plugin";
|
||||
import TerserWebpackPlugin from "terser-webpack-plugin";
|
||||
import { isDevelopment, isProduction, outDir, rendererDir } from "./src/common/vars";
|
||||
import { manifestPath, externalPackages } from "./webpack.dll";
|
||||
|
||||
export default function (): webpack.Configuration {
|
||||
const tsConfigFile = path.resolve("./tsconfig.json");
|
||||
const htmlTemplate = path.resolve(rendererDir, "template.html");
|
||||
const sassCommonVars = path.resolve(rendererDir, "components/vars.scss");
|
||||
|
||||
return {
|
||||
target: "electron-renderer",
|
||||
mode: isProduction ? "production" : "development",
|
||||
devtool: isProduction ? "source-map" : "cheap-eval-source-map",
|
||||
cache: isDevelopment,
|
||||
externals: externalPackages,
|
||||
entry: {
|
||||
renderer: path.resolve(rendererDir, "index.tsx"),
|
||||
// renderer_vue: path.resolve(rendererDir, "_vue/index.js"),
|
||||
},
|
||||
output: {
|
||||
path: outDir,
|
||||
publicPath: '/',
|
||||
filename: '[name].js',
|
||||
chunkFilename: 'chunks/[name].js',
|
||||
},
|
||||
resolve: {
|
||||
extensions: [
|
||||
'.js', '.jsx', '.json',
|
||||
'.ts', '.tsx', '.vue'
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
minimizer: [
|
||||
new TerserWebpackPlugin({
|
||||
cache: true,
|
||||
parallel: true,
|
||||
sourceMap: true,
|
||||
extractComments: {
|
||||
condition: "some",
|
||||
banner: [
|
||||
`Lens - The Kubernetes IDE. Copyright ${new Date().getFullYear()} by Lakend Labs, Inc. All rights reserved.`
|
||||
].join("\n")
|
||||
}
|
||||
})
|
||||
],
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.node$/,
|
||||
use: "node-loader"
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: [
|
||||
"babel-loader",
|
||||
{
|
||||
loader: "ts-loader",
|
||||
options: {
|
||||
transpileOnly: false,
|
||||
appendTsSuffixTo: [/\.vue$/], // todo: remove after migration vue parts
|
||||
configFile: tsConfigFile,
|
||||
compilerOptions: {
|
||||
// localization support
|
||||
// https://lingui.js.org/guides/typescript.html
|
||||
jsx: "preserve",
|
||||
target: "es2016",
|
||||
},
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(jpg|png|svg|map|ico)$/,
|
||||
use: 'file-loader?name=assets/[name]-[hash:6].[ext]'
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|woff2?)$/,
|
||||
use: 'file-loader?name=fonts/[name].[ext]'
|
||||
},
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: [
|
||||
isProduction ? MiniCssExtractPlugin.loader : "style-loader",
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
sourceMap: !isProduction
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: "sass-loader",
|
||||
options: {
|
||||
sourceMap: !isProduction,
|
||||
prependData: `@import "${path.basename(sassCommonVars)}";`,
|
||||
sassOptions: {
|
||||
includePaths: [
|
||||
path.dirname(sassCommonVars)
|
||||
]
|
||||
},
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
plugins: [
|
||||
...(isDevelopment ? [
|
||||
new webpack.HotModuleReplacementPlugin()
|
||||
] : []),
|
||||
|
||||
// provide access to external libraries, e.g. react, moment, etc.
|
||||
new webpack.DllReferencePlugin({
|
||||
context: __dirname,
|
||||
manifest: require(manifestPath),
|
||||
}),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
template: htmlTemplate,
|
||||
inject: true,
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].css",
|
||||
}),
|
||||
],
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user