@ima/cli
Version:
IMA.js CLI tool to build, develop and work with IMA.js applications.
200 lines (199 loc) • 7.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.builder = exports.handler = exports.describe = exports.command = void 0;
const path_1 = __importDefault(require("path"));
const logger_1 = require("@ima/dev-utils/logger");
const better_opn_1 = __importDefault(require("better-opn"));
const chalk_1 = __importDefault(require("chalk"));
const kill_port_1 = __importDefault(require("kill-port"));
const nodemon_1 = __importDefault(require("nodemon"));
const webpack_1 = __importDefault(require("webpack"));
const devServer_1 = require("../dev-server/devServer");
const cli_1 = require("../lib/cli");
const compiler_1 = require("../lib/compiler");
const languages_1 = require("../webpack/languages");
const utils_1 = require("../webpack/utils");
/**
* Starts ima server with nodemon to watch for server-side changes
* (all changes in server/ folder), to automatically restart the application
* server in case any change is detected.
*/
function startNodemon(args, environment) {
let serverHasStarted = false;
(0, nodemon_1.default)({
script: path_1.default.join(args.rootDir, 'server/server.js'),
watch: ['server', 'build/static/public/spa.html'].map(p => path_1.default.join(args.rootDir, p)),
args: args.verbose ? [`--verbose=${args.verbose}`] : [],
nodeArgs: args.inspect ? [`--inspect`] : [],
cwd: args.rootDir,
})
.on('start', () => {
logger_1.logger.info(`${serverHasStarted ? 'Restarting' : 'Starting'} application server${!serverHasStarted && args.forceSPA
? ` in ${chalk_1.default.black.bgCyan('SPA mode')}`
: ''}...`);
if (process.env.IMA_CLI_OPEN !== 'false' &&
args.open &&
!serverHasStarted) {
serverHasStarted = true;
const port = environment.$Server.port;
const openUrl = args.openUrl ??
process.env.IMA_CLI_OPEN_URL ??
`http://localhost:${port}`;
try {
(0, better_opn_1.default)(openUrl);
}
catch (error) {
logger_1.logger.error(`Could not open ${openUrl} inside a browser, ${error}`);
}
}
})
.on('crash', () => {
logger_1.logger.error('Application watcher crashed unexpectedly.');
});
}
/**
* Builds ima application in watch mode
* while also starting the webserver itself.
*
* @param {ImaCliArgs} args
* @returns {Promise<void>}
*/
const dev = async (args) => {
process.env.IMA_CLI_WATCH = 'true';
// Set write to disk flag, so we can disable static proxy in the application
if (args.writeToDisk) {
process.env.IMA_CLI_WRITE_TO_DISK = 'true';
}
// Set force SPA flag so server can react accordingly
if (args.forceSPA) {
process.env.IMA_CLI_FORCE_SPA = 'true';
}
// Set lazy server flag according to CLI args
if (args.lazyServer) {
process.env.IMA_CLI_LAZY_SERVER = 'true';
}
// Set legacy argument to true by default when we're forcing legacy
if (args.forceLegacy) {
args.legacy = true;
}
try {
// Do cleanup
await (0, utils_1.cleanup)(args);
// Load ima config & env
const imaConfig = await (0, utils_1.resolveImaConfig)(args);
const environment = (0, utils_1.resolveEnvironment)(args.rootDir);
/**
* Set public env variable which is used to load assets in the SSR error view.
* CLI Args should always override the config values.
*/
const devServerConfig = (0, utils_1.createDevServerConfig)({ imaConfig, args });
process.env.IMA_CLI_DEV_SERVER_PUBLIC_URL = devServerConfig.publicUrl;
// Kill processes running on the same port
await Promise.all([
(0, kill_port_1.default)(environment.$Server.port),
(0, kill_port_1.default)(devServerConfig.port),
]);
// Run preProcess hook on IMA CLI Plugins
await (0, utils_1.runImaPluginsHook)(args, imaConfig, 'preProcess');
// Compile language files
logger_1.logger.info(`Compiling language files...`, { trackTime: true });
await (0, languages_1.compileLanguages)(imaConfig, args.rootDir, true);
logger_1.logger.endTracking();
// Generate webpack config
const config = await (0, utils_1.createWebpackConfig)(args, imaConfig);
logger_1.logger.info(`Running webpack watch compiler${args.legacy
? ` ${chalk_1.default.black.bgCyan(`in${args.forceLegacy ? ' forced' : ''} legacy mode`)}`
: ''}...`);
// Create compiler
const compiler = (0, webpack_1.default)(config);
// Start watch compiler & HMR dev server
await Promise.all([
(0, compiler_1.watchCompiler)(compiler, args, imaConfig),
(0, devServer_1.createDevServer)({
args,
config: imaConfig,
compiler: compiler.compilers.find(({ name }) =>
// Run dev server only for client compiler with HMR enabled
name === 'client.es'),
hostname: devServerConfig.hostname,
port: devServerConfig.port,
publicUrl: devServerConfig.publicUrl,
rootDir: args.rootDir,
environment,
}),
]);
// Start nodemon and application server
startNodemon(args, environment);
}
catch (error) {
if (args.verbose) {
console.error(error);
}
else {
(0, compiler_1.handleError)(error);
}
process.exit(1);
}
};
const CMD = 'dev';
exports.command = CMD;
exports.describe = 'Run application in development watch mode';
exports.handler = (0, cli_1.handlerFactory)(dev);
exports.builder = {
...(0, cli_1.sharedArgsFactory)(CMD),
open: {
desc: 'Opens browser window after server has been started',
type: 'boolean',
default: true,
},
openUrl: {
desc: 'Custom URL used when opening browser window ',
type: 'string',
},
legacy: {
desc: 'Runs application in legacy mode',
type: 'boolean',
default: false,
},
forceLegacy: {
desc: 'Forces runner.js to execute legacy client code',
type: 'boolean',
default: false,
},
forceSPA: {
desc: 'Forces application to run in SPA mode',
type: 'boolean',
default: false,
},
writeToDisk: {
desc: 'Write static files to disk, instead of serving it from memory',
type: 'boolean',
default: false,
},
reactRefresh: {
desc: 'Enable/disable react fast refresh for React components',
type: 'boolean',
default: true,
},
lazyServer: {
desc: 'Enable/disable lazy init of server app factory',
type: 'boolean',
default: true,
},
port: {
desc: 'Dev server port (overrides ima.config.js settings)',
type: 'number',
},
hostname: {
desc: 'Dev server hostname (overrides ima.config.js settings)',
type: 'string',
},
publicUrl: {
desc: 'Dev server publicUrl (overrides ima.config.js settings)',
type: 'string',
},
...(0, cli_1.resolveCliPluginArgs)(CMD),
};