Skip to content

Commit

Permalink
fix(maleo-core): show error message for dev build
Browse files Browse the repository at this point in the history
move the callback function to after showing error message for development build

fix airyrooms#153

feat(maleo-core): split dev server to a new file

move dev server to a new file for single responsibility priniciple

feat(dev-server): refactor server options

feat(dev-server): add minimal build for development server

minimal build is used for faster development build

feat(maleo-server): add lazy load functionality

add lazy build functionality but not applied yet, due to missing knowledge regarding lazy building

re airyrooms#157
  • Loading branch information
alvinkl committed Apr 2, 2019
1 parent 14d0c18 commit 8a228bd
Show file tree
Hide file tree
Showing 15 changed files with 504 additions and 143 deletions.
11 changes: 0 additions & 11 deletions example/playground/src/Search/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import * as React from 'react';
import Loadable from 'react-loadable';

const DetailComponent = Loadable({
loading: () => <div>loading getting detail...</div>,
loader: () => import('src/Detail' /* webpackChunkName:"Detail" */),
modules: ['./src/Detail'],
});

export class RoomsSearch extends React.Component<any, any> {
static displayName = 'RoomsSearch';

Expand All @@ -29,11 +23,6 @@ export class RoomsSearch extends React.Component<any, any> {
}}>
<h1>Rooms Search</h1>
{this.props.children}

<br />
<br />
<br />
<DetailComponent />
</div>
);
}
Expand Down
6 changes: 5 additions & 1 deletion packages/Maleo.js/server.js
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
module.exports = require('./lib/server/server.js');
if (process.env.NODE_ENV === 'development') {
module.exports = require('./lib/server/dev-server.js');
} else {
module.exports = require('./lib/server/server');
}
1 change: 1 addition & 0 deletions packages/Maleo.js/src/bin/maleo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ if (type === 'run') {
env,
buildType: 'server',
callback: exec,
minimalBuild: true,
});
}
});
Expand Down
20 changes: 13 additions & 7 deletions packages/Maleo.js/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,22 @@ import { IBuildOptions } from '@interfaces/build/IBuildOptions';
import { Context } from '@interfaces/build/IWebpackInterfaces';

export const getConfigs = (options: IBuildOptions): Configuration[] => {
const { env, buildType } = options;
const { env, buildType, minimalBuild } = options;

const context: Context = {
env,
projectDir: process.cwd(),
};

const userConfig = loadUserConfig(context.projectDir);
const clientConfig = createWebpackConfig({ isServer: false, ...context }, userConfig);
const serverConfig = createWebpackConfig({ isServer: true, ...context }, userConfig);
const clientConfig = createWebpackConfig(
{ isServer: false, ...context, minimalBuild },
userConfig,
);
const serverConfig = createWebpackConfig(
{ isServer: true, ...context, minimalBuild },
userConfig,
);

if (buildType === 'server') {
return [serverConfig];
Expand All @@ -41,10 +47,6 @@ const compile = (configs: webpack.Configuration[], options: IBuildOptions) => {

if (env === 'development') {
webpackCompiler.run((err, stats) => {
if (typeof callback === 'function') {
return callback(err, stats);
}

if (err || stats.hasErrors()) {
console.log(
'Webpack compile failed! Error:',
Expand All @@ -53,6 +55,10 @@ const compile = (configs: webpack.Configuration[], options: IBuildOptions) => {

return;
}

if (typeof callback === 'function') {
return callback(err, stats);
}
});
} else {
webpackCompiler.run((err: Error, stats: webpack.Stats) => {
Expand Down
48 changes: 26 additions & 22 deletions packages/Maleo.js/src/build/webpack/plugins/stats-writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ export class StatsWriterPlugin {
// Extract dynamic assets to dynamic key

const key = 'assetsByChunkName';
stats = {
static: this.extractDynamic(stats[key], false),
dynamic: this.extractDynamic(stats[key], true),
};
stats = mapStats(stats, key);

// Transform to string
const [err, statsStr] = await to<string>(
Expand Down Expand Up @@ -68,10 +65,27 @@ export class StatsWriterPlugin {
return void callback();
}
};
}

export function to<T, U = Error>(
promise: Promise<T>,
errorExt?: object,
): Promise<[U | null, T | undefined]> {
return promise
.then<[null, T]>((data: T) => [null, data])
.catch<[U, undefined]>((err: U) => {
if (errorExt) {
Object.assign(err, errorExt);
}

return [err, undefined];
});
}

export const mapStats = (stats: any, key: string) => {
// Extract dynamic assets
extractDynamic = (stats, isDynamic = false) => {
return Object.keys(stats)
const extractDynamic = (stat, isDynamic = false) => {
return Object.keys(stat)
.filter((k) => {
const regex = /dynamic\./;
if (isDynamic) {
Expand All @@ -82,24 +96,14 @@ export class StatsWriterPlugin {
.reduce(
(p, c) => ({
...p,
[c]: stats[c],
[c]: stat[c],
}),
{},
);
};
}

export function to<T, U = Error>(
promise: Promise<T>,
errorExt?: object,
): Promise<[U | null, T | undefined]> {
return promise
.then<[null, T]>((data: T) => [null, data])
.catch<[U, undefined]>((err: U) => {
if (errorExt) {
Object.assign(err, errorExt);
}

return [err, undefined];
});
}
return {
static: extractDynamic(stats[key], false),
dynamic: extractDynamic(stats[key], true),
};
};
98 changes: 60 additions & 38 deletions packages/Maleo.js/src/build/webpack/webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const defaultUserConfig: CustomConfig = {
};

export const createWebpackConfig = (context: Context, customConfig: CustomConfig) => {
const { env, isServer } = context;
const { env, isServer, minimalBuild } = context;
const {
cache,
buildDir,
Expand Down Expand Up @@ -91,6 +91,7 @@ export const createWebpackConfig = (context: Context, customConfig: CustomConfig
analyzeBundle,
buildDirectory,
name,
minimalBuild,
};

const [entry, optimization, rules, plugins, output] = [
Expand Down Expand Up @@ -202,7 +203,7 @@ export const getDefaultEntry = (
context: BuildContext,
customConfig: CustomConfig,
): Configuration['entry'] => {
const { isServer, projectDir, isDev } = context;
const { isServer, projectDir, isDev, minimalBuild } = context;

const { routes, document, wrap, app } = getStaticEntries(context, customConfig);

Expand All @@ -212,13 +213,22 @@ export const getDefaultEntry = (
? path.join(projectDir, SERVER_ENTRY_NAME)
: path.resolve(__dirname, '../../../lib/default/_server.js');

return {
const serverEntries = {
server: [isDev && 'webpack/hot/signal', serverEntry].filter(Boolean) as string[],
routes,
document,
wrap,
app,
};

if (minimalBuild) {
console.log('[Webpack] Running minimal server build');
return {
server: serverEntries.server,
};
}

return serverEntries;
}

const customClientExist = fileExist(projectDir, path.join(projectDir, 'client'));
Expand Down Expand Up @@ -258,25 +268,25 @@ export const getDefaultOptimizations = (
let clientOptimizations: Configuration['optimization'];
clientOptimizations = {
...commonOptimizations,

runtimeChunk: {
name: RUNTIME_CHUNK_FILE,
},
runtimeChunk: { name: RUNTIME_CHUNK_FILE },
splitChunks: {
chunks: 'all',
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
name: false,
cacheGroups: {
default: false,
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
// test: /node_modules\/(?!((.*)webpack(.*))).*/,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];

// npm package names are URL-safe, but some servers don't like @ symbols
return `npm.${packageName.replace('@', '')}`;
},
priority: -10,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
Expand All @@ -285,7 +295,38 @@ export const getDefaultOptimizations = (
if (!isDev) {
clientOptimizations = {
...clientOptimizations,

splitChunks: {
chunks: 'all',
name: false,
minSize: 30000,
maxSize: 0,
cacheGroups: {
default: false,
vendors: false,
react: {
name: 'react',
chunks: 'all',
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
},
commons: { name: 'commons', chunks: 'all', minChunks: 2 },
},
},
// chunks: 'async', // splitChunks: {
// cacheGroups: {
// default: false,
// vendors: {
// test: /[\\/]node_modules[\\/]/,
// name(module) {
// // get the name. E.g. node_modules/packageName/not/this/part.js
// // or node_modules/packageName
// const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];

// // npm package names are URL-safe, but some servers don't like @ symbols
// return `npm.${packageName.replace('@', '')}`;
// },
// },
// },
// },
minimize: true,
minimizer: [
new TerserPlugin({
Expand All @@ -309,25 +350,6 @@ export const getDefaultOptimizations = (
},
}),
],

splitChunks: {
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,

commons: {
name: 'commons',
chunks: 'all',
minChunks: 2,
},
react: {
name: 'commons',
chunks: 'all',
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
},
},
},
};
}

Expand Down
8 changes: 7 additions & 1 deletion packages/Maleo.js/src/default/_server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { Server } from '~/src/server/server';

let SelectedServer = Server;
// No need to load DevServer code for production server
if (__DEV__) {
SelectedServer = require('~/src/server/dev-server').default;
}

const PORT = process.env.PORT || 3000;

const defaultServer = Server.init({
const defaultServer = SelectedServer.init({
port: PORT,
});

Expand Down
1 change: 1 addition & 0 deletions packages/Maleo.js/src/interfaces/build/IBuildOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import webpack from 'webpack';
export interface IBuildOptions {
env: 'development' | 'production' | 'none';
buildType: 'server' | 'client' | 'all';
minimalBuild?: boolean;
callback?: (err: Error, stats: webpack.Stats) => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface Context {
isServer?: boolean;
env: 'development' | 'production' | 'none';
projectDir: string;
minimalBuild?: boolean;
}

export interface CustomConfig {
Expand Down
11 changes: 11 additions & 0 deletions packages/Maleo.js/src/interfaces/render/IRender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ export interface RenderParam {
renderPage?: (
param: RenderPageParams,
) => (fn?: ModPageFn) => Promise<{ html: string; bundles: LoadableBundles[] }>;

preloadScripts: (
dir: string,
tempArray: any[],
context: PreloadScriptContext,
) => any[] | Promise<any[]>;
}

export interface PreloadScriptContext {
req: Request;
res: Response;
}

export interface RenderPageParams {
Expand Down
8 changes: 0 additions & 8 deletions packages/Maleo.js/src/interfaces/server/IOptions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import { DocumentProps, AppProps } from '../render/IRender';

export interface IOptions {
port: number | string;

assetDir?: string;
routes?: [];

_document?: React.ReactElement<DocumentProps>;
_app?: React.ReactElement<AppProps>;
_wrap?: React.ReactElement<any>;
}
Loading

0 comments on commit 8a228bd

Please sign in to comment.