Operations 14 min read

Automate Front‑End Asset Deployment with a Plug‑and‑Play FTP CLI Tool

This article explains how to build a three‑package monorepo using Lerna and TypeScript that automates versioned CDN uploads, FTP resource publishing, and HTML link replacement for legacy front‑end projects, providing step‑by‑step guidance and reusable CLI commands.

AutoHome Frontend
AutoHome Frontend
AutoHome Frontend
Automate Front‑End Asset Deployment with a Plug‑and‑Play FTP CLI Tool

Introduction

Legacy projects often still use a non‑separated front‑end architecture where static assets (CSS, JS, images) must be uploaded to a CDN and HTML files updated with the new resource URLs. Manual FTP uploads and version management are error‑prone, especially when multiple features are being tested and released simultaneously.

To eliminate human mistakes, a plug‑and‑play tool is required that can, in three steps, publish a specified local folder from the project root.

Install the tool package.

Add an FTP configuration file.

Add npm scripts for publishing.

Requirement Analysis

After front‑end development, a typical page folder looks like:

/page-1
    /css
    /js
    /img
    page-1.html

The desired CDN layout is versioned:

/page-1
    /v1.0.0
        /css
        /js
        /img
    /v1.0.1
        ...

Test and production environments have different upload strategies.

CDN Test Environment

The tool reads existing version directories, determines the highest version, and increments the version (patch, minor, or major) based on user choice.

CDN Production Environment

Resources are copied from the test environment to production using the selected version. Publishing fails if the test version does not exist or the production version already exists, ensuring only incremental updates.

Business‑Specific HTML Intranet Test Environment

After CDN links are replaced, the HTML pages are uploaded to a business‑specific FTP server for backend consumption.

Architecture Design

The solution consists of three npm packages managed in a Lerna monorepo:

@auto/ftp-tools-common : Handles static resource CDN upload and version management.

@auto/ftp-tools-2sc : Extends the common package with HTML upload and business‑specific requirements.

@auto/ftp-tools-utils : Shared utilities (logging, directory handling, FTP helpers) used by both packages.

The monorepo structure:

/FTP-TOOLS
    /.vscode
    /node_modules
    /packages
        /ftp-tools-2sc
        /ftp-tools-common
        /ftp-tools-utils
    .eslintrc.js
    .prettierrc
    lerna.json
    package.json

Lerna’s independent mode allows each package to be versioned and published separately. Running lerna publish updates only the changed packages and maintains correct dependency versions.

Project Setup

The toolchain uses Rollup for bundling and TypeScript as the development language.

Util Package and FTP Interface

The ftp-tools-utils package contains three source files:

/src
    ftp.ts
    index.ts
    util.ts
util.ts

exports logging classes, directory utilities, and Git branch helpers. ftp.ts exports all FTP‑related functions.

Key npm Dependencies

basic-ftp : Provides FTP connection, directory listing, and file transfer.

semver : Implements semantic version handling for validation and incrementing.

compare-versions : Sorts semver‑compatible version strings.

Example: Determining the New Version

/**
 * Get the new version for the current release
 * @param {NewVersionType} params
 */
export async function getNewVersion({ client, dir, release = 'patch' }: NewVersionType) {
  let newVersion = 'v1.0.0';
  await client.ensureDir(dir);
  const list = await client.list();
  const newList = list
    .filter(({ type, name }) => type === 2 && semver.valid(name))
    .map(({ name }) => name);
  if (newList.length > 0) {
    const greatestVersion = newList.sort(compareVersions)[newList.length - 1];
    newVersion = 'v' + semver.inc(greatestVersion, release);
  }
  return newVersion;
}

All utilities are re‑exported from src/index.ts:

export * as utils from './util';
export * as ftp from './ftp';

Common FTP Tool Package

This package implements the CLI logic for both test and production environments.

Test Environment Publishing Flow

User interaction via inquirer to select the folder and version bump type.

FTP operations to fetch the latest version, create the version directory, and upload resources.

Replace local HTML links with CDN URLs that include the new version.

Sample interaction code:

const { folder, release } = await inquirer.prompt([
  { type: 'input', name: 'folder', message: 'Enter the local folder path' },
  { type: 'list', name: 'release', message: 'Select version part to bump', choices: [
    { name: 'Patch', value: 'patch' },
    { name: 'Minor', value: 'minor' },
    { name: 'Major', value: 'major' }
  ]}
]);

Uploading resources to the versioned directory:

export async function uploadResource({ client, newVersion, remoteDir, localDir }: uploadResourceType) {
  const remoteDirWithVersion = path.join(remoteDir, newVersion);
  const localSubDirArr = getDirectories(localDir);
  for (let i = 0; i < localSubDirArr.length; i++) {
    const localSubDir = localSubDirArr[i];
    const folderName = getFolderName(localSubDir);
    await client.ensureDir(path.join(remoteDirWithVersion, folderName));
    await client.uploadFromDir(localSubDir);
  }
}

Replacing HTML resource links with the new CDN path:

const publicPath = ftp_test.publicPath + path.join(folderName, newVersion, '/');
glob.sync(`${folderPath}/*.html`).forEach(async (filepath) => {
  const htmlContent = fs.readFileSync(filepath, 'utf8');
  const cssReg = /\.\/css\/[^.]*\.css/g;
  const jsReg = /\.\/js\/[^.]*\.js/g;
  const imgReg = /\.\/img\/[^.]*\.(png|jpg|jpeg|gif)/g;
  const newHtmlContent = htmlContent
    .replace(cssReg, item => item.replace('./', publicPath))
    .replace(jsReg, item => item.replace('./', publicPath))
    .replace(imgReg, item => item.replace('./', publicPath));
  fs.writeFileSync(filepath, newHtmlContent, 'utf8');
});
CLI interaction screenshot
CLI interaction screenshot

Production Environment Publishing Flow

The logic mirrors the test flow, but before publishing it verifies that the selected version exists in the test environment and does not already exist in production, preventing overwrites.

CLI Entry Configuration

The package.json defines the executable:

{
  "main": "dist/index.js",
  "bin": { "ftp-tools-common": "bin/index.js" },
  "files": ["bin/", "dist/"]
}

Executable stub ( bin/index.js):

#!/usr/bin/env node
require('../dist/cli.js');

CLI implementation ( src/cli.ts) dispatches based on the argument:

import mainTest from './publishToTest';
import mainOnline from './publishToOnLine';
const param = process.argv[2];
if (param === '--test') {
  mainTest();
} else if (param === '--online') {
  mainOnline();
} else {
  throw new Error('Parameters are required');
}

After installing @auto/ftp-tools-common, a front‑end project adds npm scripts:

"scripts": {
  "publish:test": "ftp-tools-common --test",
  "publish:online": "ftp-tools-common --online"
}
Publishing command screenshot
Publishing command screenshot

Business‑Specific Tool Package

The @auto/ftp-tools-2sc package adds features such as uploading HTML to a dedicated web test server, performing OA identity verification, and retrieving the current Git branch to handle branch‑specific testing. These extensions are tightly coupled to the business line and are not detailed here.

Conclusion

The described monorepo provides a reusable, version‑aware FTP deployment solution that automates static asset publishing for legacy front‑end projects. Both the common and business‑specific packages are already in production and can be further extended with additional custom tools as needed.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CLITypeScriptdeploymentLernaversioningFTP
AutoHome Frontend
Written by

AutoHome Frontend

AutoHome Frontend Team

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.