Skip to content
Permalink
Browse files

feat(plugin-webpack): new webpack plugin

  • Loading branch information
MarshallOfSound committed May 4, 2018
1 parent 67d6310 commit 531d3c80f89a9c652efca2f93914c7f26c88646a
@@ -50,9 +50,12 @@
"electron-osx-sign": "^0.4.10",
"electron-packager": "^12.0.1",
"electron-rebuild": "^1.6.0",
"express": "^4.16.2",
"form-data": "^2.1.4",
"fs-extra": "^5.0.0",
"glob": "^7.1.1",
"global": "^4.3.2",
"html-webpack-plugin": "^2.30.1",
"inquirer": "^5.0.0",
"lodash.merge": "^4.6.0",
"lodash.template": "^4.4.0",
@@ -71,6 +74,10 @@
"source-map-support": "^0.5.4",
"sudo-prompt": "^8.0.0",
"username": "^3.0.0",
"webpack": "^3.11.0",
"webpack-dev-middleware": "^2.0.5",
"webpack-hot-middleware": "^2.21.0",
"webpack-merge": "^4.1.1",
"yarn-or-npm": "^2.0.2"
},
"devDependencies": {
@@ -87,10 +94,12 @@
"@types/debug": "^0.0.30",
"@types/electron-packager": "^10.1.0",
"@types/electron-winstaller": "^2.6.1",
"@types/express": "^4.11.1",
"@types/fetch-mock": "^6.0.1",
"@types/form-data": "^2.2.1",
"@types/fs-extra": "^5.0.2",
"@types/glob": "^5.0.35",
"@types/html-webpack-plugin": "^2.30.3",
"@types/inquirer": "^0.0.41",
"@types/lodash.merge": "^4.6.3",
"@types/lodash.template": "^4.4.3",
@@ -105,6 +114,10 @@
"@types/proxyquire": "^1.3.28",
"@types/semver": "^5.5.0",
"@types/sinon": "^4.3.1",
"@types/webpack": "^4.1.4",
"@types/webpack-dev-middleware": "^2.0.1",
"@types/webpack-hot-middleware": "^2.16.3",
"@types/webpack-merge": "^4.1.3",
"asar": "^0.14.0",
"babel-plugin-source-map-support": "^2.0.1",
"chai": "^4.0.0",
@@ -0,0 +1 @@
example
@@ -0,0 +1,33 @@
{
"name": "@electron-forge/plugin-webpack",
"version": "6.0.0-beta.8",
"description": "Webpack plugin for Electron Forge, let's you use a webpack directly in your tooling",
"repository": "https://github.com/electron-userland/electron-forge",
"author": "Samuel Attard",
"license": "MIT",
"main": "dist/WebpackPlugin.js",
"typings": "dist/WebpackPlugin.d.ts",
"scripts": {
"test": "exit 0"
},
"devDependencies": {
"chai": "^4.0.0",
"mocha": "^5.0.0"
},
"engines": {
"node": ">= 6.0"
},
"dependencies": {
"@electron-forge/async-ora": "^6.0.0-beta.8",
"@electron-forge/plugin-base": "6.0.0-beta.8",
"cross-spawn-promise": "^0.10.1",
"express": "^4.16.2",
"fs-extra": "^5.0.0",
"global": "^4.3.2",
"html-webpack-plugin": "^2.30.1",
"webpack": "^3.11.0",
"webpack-dev-middleware": "^2.0.5",
"webpack-hot-middleware": "^2.21.0",
"webpack-merge": "^4.1.1"
}
}
@@ -0,0 +1,20 @@
import { Configuration as WebpackConfiguration } from 'webpack';

export interface WebpackPluginEntryPoint {
html: string;
js: string;
name: string;
}

export interface WebpackPluginRendererConfig {
config: WebpackConfiguration | string;

prefixedEntries?: string[];

entryPoints: WebpackPluginEntryPoint[];
}

export interface WebpackPluginConfig {
mainConfig: WebpackConfiguration | string;
renderer: WebpackPluginRendererConfig;
}
@@ -0,0 +1,154 @@
import { asyncOra } from '@electron-forge/async-ora';
import PluginBase from '@electron-forge/plugin-base';
import fs from 'fs-extra';
import merge from 'webpack-merge';
import path from 'path';
import { spawnPromise } from 'spawn-rx';
import webpack, { Configuration } from 'webpack';
import webpackHotMiddleware from 'webpack-hot-middleware';
import webpackDevMiddleware from 'webpack-dev-middleware';
import express from 'express';

import HtmlWebpackPlugin, { Config } from 'html-webpack-plugin';

import { WebpackPluginConfig, WebpackPluginEntryPoint } from './Config';

const BASE_PORT = 3000;

export class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
name = 'webpack';
private isProd = false;
private baseDir!: string;

private resolveConfig = (config: Configuration | string) => {
if (typeof config === 'string') return require(config) as Configuration;
return config;
}

init = (dir: string) => {
this.baseDir = path.resolve(dir, '.webpack');
}

getHook(name: string) {
switch (name) {
case 'prePackage':
this.isProd = true;
return async () => {
await this.compileMain();
await this.compileRenderers();
};
}
return null;
}

async getMainConfig() {
const mainConfig = this.resolveConfig(this.config.mainConfig);

if (!mainConfig.entry) {
throw new Error('Required config option "entry" has not been defined');
}

const defines: { [key: string]: string; } = {};
let index = 0;
for (const entryPoint of this.config.renderer.entryPoints) {
defines[`${entryPoint.name.toUpperCase().replace(/ /g, '_')}_WEBPACK_ENTRY`] =
this.isProd
? `\`file://\$\{require('path').resolve(__dirname, '../renderer', '${entryPoint.name}', 'index.html')\}\``
: `'http://localhost:${BASE_PORT + index}'`;
index += 1;
}
return merge.smart({
devtool: 'source-map',
target: 'electron-main',
output: {
path: path.resolve(this.baseDir, 'main'),
filename: 'index.js',
libraryTarget: 'commonjs2',
},
plugins: [
new webpack.DefinePlugin(defines),
],
node: {
__dirname: false,
__filename: false,
},
}, mainConfig || {});
}

async getRendererConfig(entryPoint: WebpackPluginEntryPoint) {
const rendererConfig = this.resolveConfig(this.config.renderer.config);
const prefixedEntries = this.config.renderer.prefixedEntries || [];
return merge.smart({
devtool: 'inline-source-map',
target: 'electron-renderer',
entry: prefixedEntries.concat([
entryPoint.js,
]).concat(this.isProd ? [] : ['webpack-hot-middleware/client']),
output: {
path: path.resolve(this.baseDir, 'renderer', entryPoint.name),
filename: 'index.js',
},
node: {
__dirname: false,
__filename: false,
},
plugins: [
new HtmlWebpackPlugin({
title: entryPoint.name,
template: entryPoint.html,
}),
].concat(this.isProd ? [] : [new webpack.HotModuleReplacementPlugin()]),
}, rendererConfig);
}

async compileMain() {
await asyncOra('Compiling Main Process Code', async () => {
await new Promise(async (resolve, reject) => {
webpack(await this.getMainConfig()).run((err, stats) => {
if (err) return reject(err);
resolve();
});
});
});
}

async compileRenderers() {
for (const entryPoint of this.config.renderer.entryPoints) {
await asyncOra(`Compiling Renderer Template: ${entryPoint.name}`, async () => {
await new Promise(async (resolve, reject) => {
webpack(await this.getRendererConfig(entryPoint)).run((err, stats) => {
if (err) return reject(err);
resolve();
});
});
});
}
}

async launchDevServers() {
await asyncOra('Launch Dev Servers', async () => {
let index = 0;
for (const entryPoint of this.config.renderer.entryPoints) {
const config = await this.getRendererConfig(entryPoint);
const compiler = webpack(config);
const server = webpackDevMiddleware(compiler, {
logLevel: 'silent',
publicPath: '/',
hot: true,
historyApiFallback: true,
} as any);
const app = express();
app.use(server);
app.use(webpackHotMiddleware(compiler))
app.listen(BASE_PORT + index);
index += 1;
}
});
}

async spinDev() {
await this.compileMain();
await this.launchDevServers();
return false;
}
}

0 comments on commit 531d3c8

Please sign in to comment.
You can’t perform that action at this time.