Skip to content

Commit c37ba9f

Browse files
authored
Merge branch 'master' into webpack-5
2 parents 5eeb7a4 + 4a3d0f7 commit c37ba9f

10 files changed

+655
-109
lines changed

package-lock.json

Lines changed: 459 additions & 67 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
"css-loader": "1.0.1",
116116
"css-url-relative-plugin": "1.0.0",
117117
"cssnano": "4.1.7",
118+
"electron": "10.1.1",
118119
"eslint": "7.0.0",
119120
"eslint-loader": "4.0.2",
120121
"eslint-plugin-jsdoc": "25.4.2",

src/base.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ export class InsertScriptPlugin {
205205
export default function webpackConfigFactory(args: any): webpack.Configuration {
206206
tsnode.register({ transpileOnly: true });
207207
const isLegacy = args.legacy;
208+
const base = args.target === 'electron' ? './' : args.base || '/';
208209
const experimental = args.experimental || {};
209210
const isExperimentalSpeed = !!experimental.speed && args.mode === 'dev';
210211
const isTest = args.mode === 'unit' || args.mode === 'functional' || args.mode === 'test';
@@ -542,7 +543,7 @@ export default function webpackConfigFactory(args: any): webpack.Configuration {
542543
files: watchExtraFiles
543544
}),
544545
new ManifestPlugin(),
545-
new CssUrlRelativePlugin({ root: args.base || '/' })
546+
new CssUrlRelativePlugin({ root: base || '/' })
546547
]),
547548
module: {
548549
// `file` uses the pattern `loaderPath!filePath`, hence the regex test

src/dev.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function webpackConfig(args: any): webpack.Configuration {
2525
const experimental = args.experimental || {};
2626
const isExperimentalSpeed = !!experimental.speed;
2727
const singleBundle = args.singleBundle || isExperimentalSpeed;
28-
const base = args.base || '/';
28+
const base = args.target === 'electron' ? './' : args.base || '/';
2929

3030
const basePath = process.cwd();
3131
const config = baseConfigFactory(args);

src/dist.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ All rights reserved
3434

3535
function webpackConfig(args: any): webpack.Configuration {
3636
const basePath = process.cwd();
37-
const base = args.base || '/';
37+
const base = args.target === 'electron' ? './' : args.base || '/';
3838
const config = baseConfigFactory(args);
3939
const manifest: WebAppManifest = args.pwa && args.pwa.manifest;
4040
const { plugins, output } = config;

src/electron.config.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import ElectronPlugin from '@dojo/webpack-contrib/electron-plugin/ElectronPlugin';
2+
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
3+
4+
import * as webpack from 'webpack';
5+
import * as path from 'path';
6+
import * as fs from 'fs';
7+
8+
const basePath = process.cwd();
9+
const srcPath = path.join(basePath, 'src');
10+
const extensions = ['.ts', '.tsx', '.mjs', '.js'];
11+
const removeEmpty = (items: any[]) => items.filter((item) => item);
12+
const mainPath = path.join(srcPath, 'main.electron.ts');
13+
14+
function webpackConfig(args: any): webpack.Configuration {
15+
const experimental = args.experimental || {};
16+
const electron = args.electron || {};
17+
const isExperimentalSpeed = !!experimental.speed && args.mode === 'dev';
18+
const baseOutputPath = path.resolve('./output');
19+
const outputPath = path.join(baseOutputPath, args.mode);
20+
21+
return {
22+
name: 'electron',
23+
entry: {
24+
'main.electron': removeEmpty([
25+
'@dojo/webpack-contrib/electron-plugin/bootstrap',
26+
fs.existsSync(mainPath) ? mainPath : null
27+
])
28+
},
29+
resolveLoader: {
30+
modules: [path.resolve(__dirname, 'node_modules'), 'node_modules']
31+
},
32+
resolve: {
33+
modules: [basePath, path.join(basePath, 'node_modules')],
34+
extensions,
35+
plugins: [new TsconfigPathsPlugin({ configFile: path.join(basePath, 'tsconfig.json') })]
36+
},
37+
mode: args.mode === 'dev' ? 'development' : 'production',
38+
devtool: 'source-map',
39+
watchOptions: { ignored: /node_modules/ },
40+
target: 'electron-main',
41+
plugins: [
42+
new ElectronPlugin({
43+
electron: {
44+
browser: electron.browser || {},
45+
packaging: electron.packaging || {}
46+
},
47+
watch: !!args.watch,
48+
serve: !!args.serve,
49+
port: args.port,
50+
dist: args.mode !== 'dev'
51+
})
52+
],
53+
module: {
54+
rules: [
55+
{
56+
test: /\.(gif|png|jpe?g|svg|eot|ttf|woff|woff2|ico)$/i,
57+
loader: 'file-loader?hash=sha512&digest=hex&name=[name].[hash:base64:8].[ext]'
58+
},
59+
{
60+
test: /@dojo(\/|\\).*\.(js|mjs)$/,
61+
enforce: 'pre',
62+
loader: 'source-map-loader-cli',
63+
options: { includeModulePaths: true }
64+
},
65+
{
66+
include: srcPath,
67+
test: /\.ts(x)?$/,
68+
use: removeEmpty([
69+
{
70+
loader: 'ts-loader',
71+
options: {
72+
onlyCompileBundledFiles: true,
73+
instance: 'dojo',
74+
transpileOnly: isExperimentalSpeed,
75+
compilerOptions: {
76+
target: 'es2017',
77+
module: 'esnext',
78+
downlevelIteration: false
79+
}
80+
}
81+
}
82+
])
83+
}
84+
]
85+
},
86+
output: {
87+
chunkFilename: '[name].js',
88+
filename: '[name].js',
89+
path: outputPath
90+
}
91+
};
92+
}
93+
94+
export default webpackConfig;

src/main.ts

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ import devConfigFactory from './dev.config';
1919
import unitConfigFactory from './unit.config';
2020
import functionalConfigFactory from './functional.config';
2121
import distConfigFactory from './dist.config';
22+
import electronConfigFactory from './electron.config';
2223
import logger from './logger';
2324
import { moveBuildOptions } from './util/eject';
2425
import { readFileSync } from 'fs';
2526

26-
export const mainEntry = 'main';
2727
const packageJsonPath = path.join(process.cwd(), 'package.json');
2828
const packageJson = fs.existsSync(packageJsonPath) ? require(packageJsonPath) : {};
2929
export const packageName = packageJson.name || '';
@@ -37,20 +37,19 @@ function getLibraryName(name: string) {
3737

3838
const libraryName = packageName ? getLibraryName(packageName) : 'main';
3939

40-
const fixMultipleWatchTrigger = require('webpack-mild-compile');
4140
const hotMiddleware = require('webpack-hot-middleware');
4241
const connectInject = require('connect-inject');
4342

4443
const testModes = ['test', 'unit', 'functional'];
4544

46-
function createCompiler(config: webpack.Configuration) {
47-
const compiler = webpack(config);
48-
fixMultipleWatchTrigger(compiler);
49-
return compiler;
45+
// for some reason the MultiCompiler type doesn't include hooks, even though they are clearly defined on the
46+
// object coming back.
47+
interface MultiCompilerWithHooks extends webpack.MultiCompiler {
48+
hooks: webpack.compilation.CompilerHooks;
5049
}
5150

52-
function createWatchCompiler(config: webpack.Configuration) {
53-
const compiler = createCompiler(config);
51+
function createWatchCompiler(configs: webpack.Configuration[]) {
52+
const compiler = webpack(configs) as MultiCompilerWithHooks;
5453
const spinner = ora('building').start();
5554
compiler.hooks.invalid.tap('@dojo/cli-build-app', () => {
5655
logUpdate('');
@@ -83,18 +82,18 @@ function serveStatic(
8382
}
8483
}
8584

86-
function build(config: webpack.Configuration, args: any) {
87-
const compiler = createCompiler(config);
85+
function build(configs: webpack.Configuration[], args: any) {
86+
const compiler = webpack(configs);
8887
const spinner = ora('building').start();
89-
return new Promise<webpack.Compiler>((resolve, reject) => {
88+
return new Promise<webpack.MultiCompiler>((resolve, reject) => {
9089
compiler.run((err, stats) => {
9190
spinner.stop();
9291
if (err) {
9392
reject(err);
9493
}
9594
if (stats) {
9695
const runningMessage = args.serve ? `Listening on port ${args.port}...` : '';
97-
const hasErrors = logger(stats.toJson({ warningsFilter }), config, runningMessage, args);
96+
const hasErrors = logger(stats.toJson({ warningsFilter }), configs, runningMessage, args);
9897
if (hasErrors) {
9998
reject({});
10099
return;
@@ -125,10 +124,15 @@ function buildNpmDependencies(): any {
125124
}
126125
}
127126

128-
async function fileWatch(config: webpack.Configuration, args: any, shouldResolve = false) {
129-
return new Promise<webpack.Compiler>((resolve, reject) => {
130-
const watchOptions = config.watchOptions as webpack.Compiler.WatchOptions;
131-
const compiler = createWatchCompiler(config);
127+
function fileWatch(configs: webpack.Configuration[], args: any, shouldResolve = false): Promise<webpack.MultiCompiler> {
128+
const [mainConfig] = configs;
129+
let compiler: webpack.MultiCompiler;
130+
131+
return new Promise<webpack.MultiCompiler>((resolve, reject) => {
132+
const watchOptions = mainConfig.watchOptions as webpack.Compiler.WatchOptions;
133+
134+
compiler = createWatchCompiler(configs);
135+
132136
compiler.watch(watchOptions, (err, stats) => {
133137
if (err) {
134138
reject(err);
@@ -139,7 +143,7 @@ async function fileWatch(config: webpack.Configuration, args: any, shouldResolve
139143
args.port
140144
}\nPlease note the serve option is not intended to be used to serve applications in production.`
141145
: 'watching...';
142-
logger(stats.toJson({ warningsFilter }), config, runningMessage, args);
146+
logger(stats.toJson({ warningsFilter }), configs, runningMessage, args);
143147
}
144148
if (shouldResolve) {
145149
resolve(compiler);
@@ -148,8 +152,9 @@ async function fileWatch(config: webpack.Configuration, args: any, shouldResolve
148152
});
149153
}
150154

151-
async function serve(config: webpack.Configuration, args: any) {
152-
const compiler = args.watch ? await fileWatch(config, args, true) : await build(config, args);
155+
async function serve(configs: webpack.Configuration[], args: any) {
156+
const [mainConfig] = configs;
157+
153158
let isHttps = false;
154159
const base = args.base || '/';
155160

@@ -162,19 +167,21 @@ async function serve(config: webpack.Configuration, args: any) {
162167
next();
163168
});
164169

165-
const outputDir = (config.output && config.output.path) || process.cwd();
170+
const compiler = args.watch ? await fileWatch(configs, args, true) : await build(configs, args);
171+
172+
const outputDir = (mainConfig.output && mainConfig.output.path) || process.cwd();
166173
let btrOptions = args['build-time-render'];
167174
if (btrOptions) {
168175
if (args.singleBundle || (args.experimental && !!args.experimental.speed)) {
169176
btrOptions = { ...btrOptions, sync: true };
170177
}
171-
const jsonpName = (config.output && config.output.jsonpFunction) || 'unknown';
178+
const jsonpName = (mainConfig.output && mainConfig.output.jsonpFunction) || 'unknown';
172179
const onDemandBtr = new OnDemandBtr({
173180
buildTimeRenderOptions: btrOptions,
174181
scope: libraryName,
175182
base,
176-
compiler,
177-
entries: config.entry ? Object.keys(config.entry) : [],
183+
compiler: compiler.compilers[0],
184+
entries: mainConfig.entry ? Object.keys(mainConfig.entry) : [],
178185
outputPath: outputDir,
179186
jsonpName
180187
});
@@ -296,6 +303,13 @@ const command: Command = {
296303
choices: ['dist', 'dev', 'test', 'unit', 'functional']
297304
});
298305

306+
options('target', {
307+
describe: 'the target',
308+
alias: 't',
309+
default: 'web',
310+
choices: ['web', 'electron']
311+
});
312+
299313
options('watch', {
300314
describe: 'watch for file changes',
301315
alias: 'w'
@@ -356,31 +370,39 @@ const command: Command = {
356370
},
357371
run(helper: Helper, args: any) {
358372
console.log = () => {};
359-
let config: webpack.Configuration;
373+
let configs: webpack.Configuration[] = [];
360374
args.experimental = args.experimental || {};
375+
args.base = url.resolve('/', args.base || '');
376+
if (!args.base.endsWith('/')) {
377+
args.base = `${args.base}/`;
378+
}
361379

362380
if (args.mode === 'dev') {
363-
config = devConfigFactory(args);
381+
configs.push(devConfigFactory(args));
364382
} else if (args.mode === 'unit' || args.mode === 'test') {
365-
config = unitConfigFactory(args);
383+
configs.push(unitConfigFactory(args));
366384
} else if (args.mode === 'functional') {
367-
config = functionalConfigFactory(args);
385+
configs.push(functionalConfigFactory(args));
368386
} else {
369-
config = distConfigFactory(args);
387+
configs.push(distConfigFactory(args));
388+
}
389+
390+
if (args.target === 'electron') {
391+
configs.push(electronConfigFactory(args));
370392
}
371393

372394
if (args.serve) {
373395
if (testModes.indexOf(args.mode) !== -1) {
374396
return Promise.reject(new Error(`Cannot use \`--serve\` with \`--mode=${args.mode}\``));
375397
}
376-
return serve(config, args);
398+
return serve(configs, args);
377399
}
378400

379401
if (args.watch) {
380-
return fileWatch(config, args);
402+
return fileWatch(configs, args);
381403
}
382404

383-
return build(config, args);
405+
return build(configs, args);
384406
},
385407
eject(helper: Helper): EjectOutput {
386408
return {

src/schema.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99
"functional"
1010
]
1111
},
12+
"target": {
13+
"type": "string",
14+
"enum": [
15+
"web",
16+
"electron"
17+
]
18+
},
1219
"watch": {
1320
"type": "boolean"
1421
},
@@ -63,6 +70,13 @@
6370
}
6471
}
6572
},
73+
"electron": {
74+
"properties": {
75+
"browser": {
76+
"type": "object"
77+
}
78+
}
79+
},
6680
"build-time-render": {
6781
"additionalProperties": false,
6882
"properties": {
@@ -445,6 +459,12 @@
445459
"m": {
446460
"$ref": "#/definitions/mode"
447461
},
462+
"target": {
463+
"$ref": "#/definitions/target"
464+
},
465+
"t": {
466+
"$ref": "#/definitions/target"
467+
},
448468
"watch": {
449469
"$ref": "#/definitions/watch"
450470
},
@@ -522,6 +542,9 @@
522542
{ "$ref": "#/definitions/imageOptimizationOptions" },
523543
{ "$ref": "#/definitions/imageOptimizationFlag" }
524544
]
545+
},
546+
"electron": {
547+
"$ref": "#/definitions/electron"
525548
}
526549
}
527550
}

test-app/.dojorc-dev-app

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"build-app": {
3-
"base": "/test-app/output/dev-app/",
3+
"base": "test-app/output/dev-app",
44
"mode": "dev",
55
"legacy": true,
66
"compression": [ "gzip", "brotli" ],

0 commit comments

Comments
 (0)