Skip to content

Commit

Permalink
feat(ui-devkit): Allow static assets to be renamed
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed Mar 16, 2020
1 parent 3d08460 commit 08e23d0
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 20 deletions.
3 changes: 3 additions & 0 deletions packages/ui-devkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,15 @@
"@angular/cli": "^9.0.5",
"@angular/compiler": "^9.0.6",
"@angular/compiler-cli": "^9.0.6",
"@vendure/admin-ui": "^0.9.0",
"@vendure/common": "^0.9.0",
"chokidar": "^3.0.2",
"fs-extra": "^8.1.0",
"rxjs": "^6.5.4"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^6.0.0",
"@types/fs-extra": "^8.1.0",
"@vendure/core": "^0.9.0",
"rimraf": "^3.0.0",
"rollup": "^1.27.9",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-devkit/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default commandLineArgs => {
output: {
dir: 'client',
format: 'umd',
name: 'VendureUiDevkit',
name: 'VendureUiClient',
},
plugins: [resolve(), typescript(), ...(isProd ? [terser({
output: {
Expand Down
3 changes: 2 additions & 1 deletion packages/ui-devkit/scaffold/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@
"assets": [
"src/favicon.ico",
"src/vendure-ui-config.json",
"src/theme.min.css",
"src/assets",
"src/i18n-messages",
{
"glob": "**/*.*",
"input": "src/extensions/static-assets",
"input": "static-assets",
"output": "assets"
}
],
Expand Down
66 changes: 49 additions & 17 deletions packages/ui-devkit/src/compiler/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
AdminUiExtension,
AdminUiExtensionLazyModule,
AdminUiExtensionSharedModule,
StaticAssetDefinition,
UiExtensionCompilerOptions,
} from './types';

Expand Down Expand Up @@ -79,7 +80,7 @@ function runWatchMode(
new Promise<void>(async (resolve, reject) => {
await setupScaffold(outputPath, extensions);
const normalizedExtensions = normalizeExtensions(extensions);
buildProcess = spawn(cmd, ['run', 'start', `--port=${port}`, `--poll=1000`], {
buildProcess = spawn(cmd, ['run', 'start', `--port=${port}`], {
cwd: outputPath,
shell: true,
stdio: 'inherit',
Expand All @@ -103,6 +104,12 @@ function runWatchMode(
} else {
watcher.add(extension.extensionPath);
}
if (extension.staticAssets) {
for (const staticAssetDef of extension.staticAssets) {
const assetPath = getStaticAssetPath(staticAssetDef);
watcher.add(assetPath);
}
}
}

if (watcher) {
Expand All @@ -111,25 +118,28 @@ function runWatchMode(
}

if (watcher) {
watcher.on('change', filePath => {
const allStaticAssetDefs = extensions.reduce(
(defs, e) => [...defs, ...(e.staticAssets || [])],
[] as StaticAssetDefinition[],
);
watcher.on('change', async filePath => {
const extension = normalizedExtensions.find(e => filePath.includes(e.extensionPath));
if (extension) {
if (extension.staticAssets) {
for (const assetPath of extension.staticAssets) {
if (filePath.includes(assetPath)) {
copyStaticAsset(outputPath, assetPath);
return;
}
}
}
const outputDir = path.join(outputPath, MODULES_OUTPUT_DIR, extension.id);
const filePart = path.relative(extension.extensionPath, filePath);
const dest = path.join(outputDir, filePart);
fs.copyFile(filePath, dest);
await fs.copyFile(filePath, dest);
}
if (filePath.includes(devkitPath)) {
copyUiDevkit(outputPath);
}
for (const staticAssetDef of allStaticAssetDefs) {
const assetPath = getStaticAssetPath(staticAssetDef);
if (filePath.includes(assetPath)) {
await copyStaticAsset(outputPath, staticAssetDef);
return;
}
}
});
}
resolve();
Expand All @@ -151,7 +161,7 @@ function runWatchMode(
async function setupScaffold(outputPath: string, extensions: AdminUiExtension[]) {
deleteExistingExtensionModules(outputPath);
copySourceIfNotExists(outputPath);
copyExtensionModules(outputPath, normalizeExtensions(extensions));
await copyExtensionModules(outputPath, normalizeExtensions(extensions));
copyUiDevkit(outputPath);
try {
await checkIfNgccWasRun();
Expand Down Expand Up @@ -191,7 +201,10 @@ function normalizeExtensions(extensions?: AdminUiExtension[]): Array<Required<Ad
* Copies all files from the extensionPaths of the configured extensions into the
* admin-ui source tree.
*/
export function copyExtensionModules(outputPath: string, extensions: Array<Required<AdminUiExtension>>) {
export async function copyExtensionModules(
outputPath: string,
extensions: Array<Required<AdminUiExtension>>,
) {
const extensionRoutesSource = generateLazyExtensionRoutes(extensions);
fs.writeFileSync(path.join(outputPath, EXTENSION_ROUTES_FILE), extensionRoutesSource, 'utf8');
const sharedExtensionModulesSource = generateSharedExtensionModule(extensions);
Expand All @@ -203,7 +216,7 @@ export function copyExtensionModules(outputPath: string, extensions: Array<Requi
fs.copySync(extension.extensionPath, dest);
if (Array.isArray(extension.staticAssets)) {
for (const asset of extension.staticAssets) {
copyStaticAsset(outputPath, asset);
await copyStaticAsset(outputPath, asset);
}
}
}
Expand Down Expand Up @@ -263,13 +276,28 @@ function getModuleFilePath(
* static assets directory. When the app is built by the ng cli, this assets directory is
* the copied over to the final static assets location (i.e. http://domain/admin/assets/)
*/
export function copyStaticAsset(outputPath: string, staticAssetPath: string) {
export async function copyStaticAsset(outputPath: string, staticAssetDef: StaticAssetDefinition) {
const staticAssetPath = getStaticAssetPath(staticAssetDef);
const stats = fs.statSync(staticAssetPath);
let assetOutputPath: string;
if (stats.isDirectory()) {
const assetDirname = path.basename(staticAssetPath);
fs.copySync(staticAssetPath, path.join(outputPath, STATIC_ASSETS_OUTPUT_DIR, assetDirname));
assetOutputPath = path.join(outputPath, STATIC_ASSETS_OUTPUT_DIR, assetDirname);
} else {
fs.copySync(staticAssetPath, path.join(outputPath, STATIC_ASSETS_OUTPUT_DIR));
assetOutputPath = path.join(outputPath, STATIC_ASSETS_OUTPUT_DIR);
}
fs.copySync(staticAssetPath, assetOutputPath);
if (typeof staticAssetDef !== 'string') {
// The asset is being renamed
const newName = path.join(path.dirname(assetOutputPath), staticAssetDef.rename);
try {
// We use copy, remove rather than rename due to problems with the
// EPERM error in Windows.
await fs.copy(assetOutputPath, newName);
await fs.remove(assetOutputPath);
} catch (e) {
console.log(e);
}
}
}

Expand Down Expand Up @@ -374,3 +402,7 @@ export function shouldUseYarn(): boolean {
return false;
}
}

function getStaticAssetPath(staticAssetDef: StaticAssetDefinition): string {
return typeof staticAssetDef === 'string' ? staticAssetDef : staticAssetDef.path;
}
11 changes: 10 additions & 1 deletion packages/ui-devkit/src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,18 @@ export interface AdminUiExtension {
* Optional array of paths to static assets which will be copied over to the Admin UI app's `/static`
* directory.
*/
staticAssets?: string[];
staticAssets?: StaticAssetDefinition[];
}

/**
* @description
* A static asset can be provided as a path to the asset, or as an object containing a path and a new
* name, which will cause the compiler to copy and then rename the asset.
*
* @docsCategory UiDevkit
*/
export type StaticAssetDefinition = string | { path: string; rename: string };

/**
* @description
* Configuration defining a single NgModule with which to extend the Admin UI.
Expand Down

0 comments on commit 08e23d0

Please sign in to comment.