@frontity/core
Version:
The core package of the Frontity framework.
195 lines (174 loc) • 5.26 kB
text/typescript
import ignore from "./utils/ts-node-ignore";
import * as tsNode from "ts-node";
/**
* This file gets transpiled to JS anyway, but if the users's
* frontity.settings.(js|ts) is an ES Module, we cannot require an ES Module
* from a commonjs module.
*
* This is why we use ts-node here as well as in the `build` script.
* It's only because we want the user to be able to use ES Modules syntax in
* the frontity.settings.(js|ts) file like this.
*
* @example
* ```js
* export default {
* name: 'my-theme',
* state: {},
* packages: {},
* }
* ```
*/
tsNode.register({
transpileOnly: true,
ignore,
compilerOptions: {
// Target latest version of ECMAScript.
target: "es2017",
// Search under node_modules for non-relative imports.
moduleResolution: "node",
// commonjs modules.
module: "commonjs",
// Allow default imports from modules with no default export.
allowSyntheticDefaultImports: true,
// Don't emit; allow Babel to transform files.
noEmit: true,
// Import non-ES modules as default imports.
esModuleInterop: true,
// Resolve JSON files.
resolveJsonModule: true,
// Support for JSX runtime.
jsx: "react-jsx",
// Support for emotion css prop with types
jsxImportSource: "@emotion/react",
// Transpile JS as well.
allowJs: true,
},
});
import "./utils/envs";
import webpack from "webpack";
import webpackDevMiddleware from "webpack-dev-middleware";
import webpackHotMiddleware from "webpack-hot-middleware";
import { getAllSites } from "@frontity/file-settings";
import createApp from "./utils/create-app";
import HotServer from "./utils/hot-server";
import generateEntryPoints from "./utils/entry-points";
import getConfig from "../config";
import getFrontity from "../config/frontity";
import { Mode } from "@frontity/types/config";
import cleanBuildFolders from "./utils/clean-build-folders";
import { webpackAsync } from "./utils/webpack";
import createSymlinks from "./utils/create-symlinks";
import { readConfigurationsFromConfigFiles } from "./utils/read-configuration";
/**
* The options of the dev command.
*/
export interface DevOptions {
/**
* The Webpack mode used, either "development" or "production".
*
* @defaultValue "development"
*/
mode: Mode;
/**
* The port used to start the server.
*
* @defaultValue 3000
*/
port: number;
/**
* Indicate if the server should be started using HTTPS. The certs used
* are in the /certs folder of this package. They are valid only for local
* usage.
*
* @defaultValue false
*/
isHttps: boolean;
/**
* The JavaScript transpilation target. Either "es5" or "module".
*
* @defaultValue "module"
*/
target: "es5" | "module";
/**
* If this command should open a browser or not.
*
* @defaultValue true
*/
openBrowser?: boolean;
/**
* The publicPath used in Webpack.
*
* @defaultValue "/static/"
*/
publicPath: string;
/**
* Indicate if the Bundle Analyzer plugin should be included in the Webpack
* configuration, in order to generate HTML files for bundle analyzing.
*
* @defaultValue false
*/
analyze?: boolean;
}
/**
* The Frontity dev command that starts a development Frontity server.
*
* @param options - Defined in {@link DevOptions}.
*
* @returns A promise that resolves when the server has started.
*/
export default async ({
isHttps,
mode,
port,
target,
openBrowser = true,
publicPath = "/static/",
analyze,
}: DevOptions): Promise<void> => {
// Get config from frontity.config.js files.
const frontityConfig = getFrontity();
const { outDir } = frontityConfig;
// Create symlinks for internal packages
await createSymlinks();
// Create the directories if they don't exist, clean them if they do.
await cleanBuildFolders({ outDir });
// Get all sites configured in frontity.settings.js with their packages.
const sites = await getAllSites();
// Generate the bundles. One for the server, one for each client site.
const entryPoints = await generateEntryPoints({ sites, outDir, mode });
// Start dev using webpack dev server with express.
const { app, done } = await createApp({
mode,
port,
isHttps,
target,
openBrowser,
publicPath,
});
// Read the extra configurations from files.
const extraConfigurations = await readConfigurationsFromConfigFiles(sites);
// Get config for webpack, babel and frontity.
const config = getConfig({
mode,
entryPoints,
analyze,
extraConfigurations,
});
// Build and wait until webpack finished the client first.
// We need to do this because the server bundle needs to import
// the client loadable-stats, which are created by the client Webpack.
const clientWebpack =
target === "es5" ? config.webpack.es5 : config.webpack.module;
await webpackAsync(clientWebpack);
// Start a custom webpack-dev-server.
const compiler = webpack([clientWebpack, config.webpack.server]);
app.use(
webpackDevMiddleware(compiler, {
writeToDisk: true,
})
);
app.use(webpackHotMiddleware(compiler.compilers[0]));
app.use(HotServer(compiler));
// Start listening once webpack finishes.
done(compiler);
};