Copying Non-Code Files to /dist in Your NodeJS Build Process

When working with Node.js and TypeScript, it’s common to encounter the need to include non-code files like JSON, text files, or even Markdown files in your build output. These files, essential for configurations, data, or documentation, often need to be copied into your dist folder during the build process. However, the TypeScript compiler (tsc) only compiles .ts files and doesn’t handle copying non-code files. To ensure these files are available post-build without manual copying, automating this process is key.

Thank me by sharing on Twitter 🙏

In this post, I’ll explain how I automated the copying of these files during my build process using the copyfiles package, ensuring the folder structure is preserved while excluding unnecessary root directories. I’ll walk through how you can set up a simple, efficient workflow that streamlines this task.

Why Automate Copying Non-Code Files?

In most Node.js projects, non-code files like .json and .txt often contain critical information such as configurations, data, or documentation that the application requires at runtime. These files need to be transferred to the build folder (dist) after the TypeScript files are compiled to ensure the complete application is bundled correctly.

Without automating this step, you might find yourself copying these files manually after every build, which is not only tedious but prone to human error. Automating this process makes sure everything is copied to the correct location without additional manual steps.

The Solution: Using copyfiles

To handle copying non-code files, I used the copyfiles package. It’s lightweight and straightforward, allowing me to specify patterns for files I want to copy, and it preserves the folder structure. Importantly, copyfiles also lets me remove certain top-level directories during the copy, which is especially useful when I want to drop the src folder while maintaining the internal folder structure.

Step 1: Installing copyfiles

The first step is to install the copyfiles package as a development dependency. Since it’s used only during the build process, it doesn’t need to be included in the production environment.

To install it, run:

ShellScript
npm install --save-dev copyfiles

This installs the package, and you can now use it in your build scripts.

Step 2: Setting Up the Build Script with -u 1

In a typical TypeScript project, your build script in package.json might look something like this:

JSON
{
  "scripts": {
    "build": "tsc"
  }
}

This script compiles the TypeScript files, but as mentioned earlier, it leaves out other important files such as .json, .txt, and .md. I needed a way to copy these files into the dist folder, maintaining their internal folder structure but excluding the src folder itself.

To do this, I updated the build script to include copyfiles with the -u 1 flag. This flag tells copyfiles to drop the top-level directory (src), so the files inside src are copied to the dist folder while maintaining their subdirectory structure.

Here’s the updated build script:

JSON
{
  "scripts": {
    "build": "tsc && copyfiles -u 1 './src/**/*.{json,txt,md}' dist"
  }
}

Let’s break this down:

  1. tsc compiles the TypeScript files into JavaScript and places them in the dist folder.
  2. copyfiles -u 1 './src/**/*.{json,txt,md}' dist copies all .json, .txt, and .md files from src to dist, preserving the folder structure while dropping the top-level src directory.

For example, a JSON file located at src/config/settings.json will be copied to dist/config/settings.json, but without the extra src/ in the destination path.

Step 3: Running the Build Script

With the build script set up, you can run the build process with the following command:

ShellScript
npm run build

After running this, all .ts files will be compiled to .js, and the .json, .txt, and .md files will be copied to the dist folder, preserving the subdirectories.

For instance, if your folder structure looks like this:

Plaintext
src/
  config/
    settings.json
  data/
    sample.txt
  docs/
    readme.md

After running the build, the dist folder will look like this:

Plaintext
dist/
  config/
    settings.json
  data/
    sample.txt
  docs/
    readme.md

As you can see, the folder structure under src/ is preserved in dist/, but the src/ folder itself is excluded.

Common Pitfalls and Troubleshooting

During the setup, I encountered a few common issues that are worth mentioning.

  1. Incorrect Usage of the -u Flag:
    If you set the -u flag too high (e.g., -u 2), you’ll get an error like: Error: cant go up that far. This error occurs because copyfiles tries to remove more directory levels than exist in the path. To fix this, ensure the -u value matches the number of top-level directories you want to exclude. In this case, -u 1 removes only the src folder.
  2. File Path Issues:
    If the files aren’t being copied as expected, double-check the file patterns you’re using. For example, ./src/**/*.{json,txt,md} ensures that all .json, .txt, and .md files inside src and its subdirectories are copied. Forgetting the ** part of the pattern will only copy files from the top-level src directory, ignoring subdirectories.
  3. Cross-Platform Compatibility:
    If you’re working in a cross-platform team, or deploying to both Linux and Windows environments, make sure your paths are compatible. For example, the forward slash (/) in the path works universally in most environments, but for Windows, ensure you use the correct escape characters if needed.

Conclusion

By using copyfiles and the -u 1 flag, I was able to automate the process of copying important non-code files such as JSON, TXT, and Markdown files during my TypeScript build process. This method ensures that my build folder includes all the necessary files while maintaining the correct directory structure, without manual intervention or complex scripts.

This small change to my build workflow has saved me time and reduced the risk of errors during deployment. If your project involves any non-code assets that need to be copied into your build output, automating the process using copyfiles is a simple yet effective solution that you can set up in just a few minutes.

Share this:

Leave a Reply