esmc
esmc

Reputation: 271

PDFMAKE: 'Roboto-Regular.ttf' not found in virtual file system ONLY AFTER GULP

I created a simple app using knockout/bootstrap/gulp that downloads a pdf using pdfMake.js. It works fine in debug mode using VS2017. After publishing and using gulp it gives this error when run: File 'Roboto-Regular.ttf' not found in virtual file system

Note: After gulp, all JS files are in one script.js file.

I tried many things, it always works when debugging, as soon as I run gulp, it gives the error.

I tried joepal1976's solution from here (what I did with the dependencies in require.config.js)

Someone suggested .pipe(uglify({ compress: { hoist_funs: false } })) which doesn't appear to help.

Included in require.config like so:

var require = {
    baseUrl: ".",
    paths: {
        "jquery":               "js-libs/jquery.min",
        "bootstrap":            "js-libs/bootstrap.min",
        "crossroads":           "js-libs/crossroads.min",
        "hasher":               "js-libs/hasher.min",
        "knockout":             "js-libs/knockout",
        "knockout-projections": "js-libs/knockout-projections.min",
        "signals":              "js-libs/signals.min",
        "text":                 "js-libs/text",
        "vfs_fonts":            "js-libs/vfs_fonts",
        "pdfMake":              "js-libs/pdfmake.min"
    },
    shim: {
        "bootstrap": { deps: ["jquery"] },
        'pdfMake':
        {
            exports: 'vfs_fonts'
        },
        'vfs_fonts':
        {
            deps: ['pdfMake'],
            exports: 'vfs_fonts'
        }
    }
};

JS for the page:

define(["knockout", "text!./home.html"], function (ko, homeTemplate) {
function HomeViewModel(route) {
    var thisVM = this;


    this.VMInit = function () {

        var thePDF = {
            content: [
                'My test invoice.',
            ]
        };

        pdfMake.createPdf(thePDF).download('pdf_test.pdf');

    }

    thisVM.VMInit();
}
return { viewModel: HomeViewModel, template: homeTemplate };

});

The Gulp file:

//-----------------------------------------------------------------------
// Node modules
var fs      = require('fs'),
vm      = require('vm'),
merge   = require('deeply'),
chalk   = require('chalk'),
es      = require('event-stream');

//-----------------------------------------------------------------------
// Gulp and plugins
var gulp        = require('gulp'),
rjs         = require('gulp-requirejs-bundler'),
concat      = require('gulp-concat'),
clean       = require('gulp-clean'),
replace     = require('gulp-replace'),
uglify      = require('gulp-uglify'),
htmlreplace = require('gulp-html-replace');

// Config
var requireJsRuntimeConfig = 
vm.runInNewContext(fs.readFileSync('src/app/require.config.js') + '; require;');
requireJsOptimizerConfig = merge(requireJsRuntimeConfig, {
    out: 'scripts.js',
    baseUrl: './src',
    name: 'app/startup',
    paths: {
        requireLib: 'js-libs/require'
    },
    include: [
        'requireLib',
        'components/nav-bar/nav-bar',
        'components/home-page/home',
        'text!components/about-page/about.html'
    ],
    insertRequire: ['app/startup'],
    bundles: {
        // If you want parts of the site to load on demand, remove them from the 'include' list
        // above, and group them into bundles here.
        // 'bundle-name': [ 'some/module', 'another/module' ],
        // 'another-bundle-name': [ 'yet-another-module' ]
    }
});

//-----------------------------------------------------------------------
// Discovers all AMD dependencies, concatenates together all required .js 
files, minifies them
gulp.task('js', function () {
    return rjs(requireJsOptimizerConfig)
        .pipe(replace('Views/src/', ''))
        .pipe(replace('img/', 'Assets/img/'))
        .pipe(replace('css/', 'Assets/css/'))
        .pipe(uglify({
            preserveComments: 'some'
        }))
        .pipe(gulp.dest('./dist-app/Assets/js/'));
});


gulp.task('css', function () {
return gulp.src(['./src/css/bootstrap.css',
                 './src/css/bootstrap-switch.css',
                 './src/css/dataTables.bootstrap.css',
                 './src/css/dataTables.colVis.css',
                 './src/css/dataTables.responsive.css',
                 './src/css/daterangePicker.css'])
    .pipe(concat('styles.css'))
    .pipe(gulp.dest('./dist-app/Assets/css/'));
});


// Copies index.html, replacing <script> and <link> tags to reference production 
URLs
gulp.task('html', function () {
return gulp.src('./src/index.html')
    .pipe(htmlreplace({
        dependencies_top: '<link href="Assets/css/styles.css" 
rel="stylesheet">',
        dependencies_bottom: '<script src="Assets/js/scripts.js"></script>'
    }))
    .pipe(gulp.dest('./dist-app/'));
});



// Removes all files from ./dist/
gulp.task('clean', function () {
console.log("the clean task");
return gulp.src('./dist-app/**/*', { read: false })
    .pipe(clean());
});

// All tasks in [] must complete before 'default' can begin
gulp.task('default', ['html', 'js', 'css'], function (callback) {
callback();
console.log('\nPlaced optimized files in ' + chalk.magenta('dist-app/\n'));
});

The Startup.js file if its helpful:

define(['jquery',
    'knockout',
    './router',
    'bootstrap',
    'knockout-projections',
    'pdfMake',
    'vfs_fonts'], function ($, ko, router) {

// Components can be packaged as AMD modules, such as the following:
ko.components.register('nav-bar', { require: 'components/nav-bar/nav-bar' });
ko.components.register('home-page', { require: 'components/home-page/home' 
});

// ... or for template-only components, you can just point to a .html file 
directly:
ko.components.register('about-page', {
template: { require: 'text!components/about-page/about.html' }
});

ko.components.register('new-page', { require: 'components/new-page/new-page' 
});

// [Scaffolded component registrations will be inserted here. To retain this 
//feature, don't remove this comment.]

// Start the application
ko.applyBindings({ route: router.currentRoute });
});

Upvotes: 27

Views: 53748

Answers (12)

dbgupta
dbgupta

Reputation: 139

Create a file: src/typings/pdfmake.d.ts

declare module 'pdfmake/build/pdfmake' {
  const pdfMake: any;
  export = pdfMake;
}

declare module 'pdfmake/build/vfs_fonts' {
  const pdfFonts: any;
  export = pdfFonts;
}

Verify Your tsconfig.json

{
  "compilerOptions": {
    "typeRoots": [
      "node_modules/@types",
      "src/typings"
    ]
  }
}

In your angular code

import pdfMake from 'pdfmake/build/pdfmake';
import pdfFonts from 'pdfmake/build/vfs_fonts';

(pdfMake as any).vfs = pdfFonts.pdfMake.vfs;

Upvotes: 0

santosh patro
santosh patro

Reputation: 13

currently i amusing this versionofpdfMake"pdfmake": "^0.2.10", and in this you cannot assign font by this pdfMake.vfs = pdfFonts.pdfMake.vfs; so whenever you write pdfMake.createPdf() inside that assign font case 'download':

pdfMake.createPdf(documentDefinition,undefined,undefined,pdfFonts.pdfMake.vfs).open(); break;

UPDATE 2025

Version: 0.2.18

pdfMake.vfs is now undefined and pdfMake.setFonts(pdfFonts.pdfMake.vfs) does not help as it throws error of 'cannot create bold with...'

Code Example

import * as pdfFonts from 'pdfmake/build/vfs_fonts';
...
pdfMake.createPdf(documentDefinition,undefined,undefined,pdfFonts).open();

Upvotes: 1

Nycolas Santana
Nycolas Santana

Reputation: 11

try this

import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";

pdfMake.vfs = pdfFonts['Roboto-Regular.ttf'];

Upvotes: 1

NitroX
NitroX

Reputation: 1

TYPESCRIPT VUE 3 2024-11-28

if you see this You might get build errors or same error as OP. Don't import pdfFonts. instead follow this.

pdfMake.fonts = { Helvetica: { normal: "Helvetica",bold: "Helvetica-Bold",italics: "Helvetica-Oblique",bolditalics: "Helvetica-BoldOblique",},}

and remember to add following to your docDefinition (TDocumentDefinitions)

defaultStyle: { font: 'Helvetica' }

what we have done is instead depending on Roboto font we used 'Helvetica' font insted, which is browser safe font(comes pre installed in most OS and web browsers). and this method only works with English Charactors. you could try to change this for your desired font but I cannot guarantee if it will work for you. read documentation for more info : https://pdfmake.github.io/docs/0.1/fonts/standard-14-fonts/

Upvotes: 0

Exac
Exac

Reputation: 53

In 2024 with version 0.2.13 you may pass the fonts as the fourth argument in createPDF:

import * as pdfFonts from 'pdfmake/build/vfs_fonts';
import * as pdfMake from 'pdfmake/build/pdfmake';

pdfMake.createPdf(docDefinition, undefined, undefined, pdfFonts.pdfMake.vfs).open();

Pass undefined instead of null as someone else suggested. Note that the import order does not actually matter.

pdfMake.vfs is not mutable, so the following does not work:

pdfMake.vfs = pdfFonts.pdfMake.vfs; // Doesn't work
(window as any).pdfMake.vfs = pdfFonts.pdfMake.vfs // Don't use

Don't forget to install the typings via

npm install -D @types/pdfmake

Upvotes: 0

GROVER.
GROVER.

Reputation: 4378

UPDATE: 2024 (Version 0.2.10)

As of the most recent update, the following code works inconsistently across different systems:

import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";
pdfMake.vfs = pdfFonts.pdfMake.vfs;

Using this will often result in virtual file-system errors and pdfFonts.pdfMake.vfs sometimes being undefined.


I have found that creating a wrapper method that points directly to the VFS data generated by pdfmake is far more reliable.

First, navigate to node_modules/pdfmake/build/vfs_fonts.js and copy the data into a new file in your repo (vfs.js) like so:

export const vfs = {
    "Roboto-Italic.ttf": "...",
    "Roboto-Medium.ttf": "...",
    "Roboto-MediumItalic.ttf": "...",
    "Roboto-Regular.ttf": "...",
}

Create the wrapper utility:

import type { CustomTableLayout } from "pdfmake/interfaces";
import type { TDocumentDefinitions } from "pdfmake/interfaces";
import pdfMake from "pdfmake/build/pdfmake";
import { vfs } from "./vfs";

export const generatePdf = (
    options: TDocumentDefinitions,
    layouts?: Record<string, CustomTableLayout>,
) => {
    // Register fonts...
    (<any>pdfMake).vfs = vfs;

    return pdfMake.createPdf({
        ...YOUR_DEFAULT_OPTIONS,
        ...options,
    });
}

Then use like so:

import { generatePdf } from "location/of/generatePdf";
const generator = generatePdf({ ... });

Upvotes: 0

Rama Jangid
Rama Jangid

Reputation: 1

Use this fonts script in ReactJs:

import pdfMake from "pdfmake/build/pdfmake.min";

pdfMake.fonts = {
    Roboto: {
      normal: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-Regular.ttf',
      bold: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-Medium.ttf',
      italics: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-Italic.ttf',
      bolditalics: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-MediumItalic.ttf'
    }
 }

Upvotes: 0

Herz3h
Herz3h

Reputation: 712

@Rijo solution worked in one file, but oddly enough refused to work in another file.

In the other file I had to use:

import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";

// Wherever you call createPdf, you have to pass VFS
pdfMake.createPdf(docDefinition, null, null, pdfFonts.pdfMake.vfs).open();

Upvotes: 3

TidyDev
TidyDev

Reputation: 3668

I came across this issue and resolved it by including vfs_fonts.js just after the pdfmake Javascript file.

Here is my code, you should just need to set the file path to wherever your copy of the file is placed.

<script src="~/Content/DataTables/pdfmake-0.1.32/pdfmake.min.js"></script>
<script src="~/Content/DataTables/pdfmake-0.1.32/vfs_fonts.js"></script>

CDN LINK

<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.32/vfs_fonts.js"></script>

please follow the hierarchy/dependency of links else it won't work

Upvotes: 15

Purplenimbus
Purplenimbus

Reputation: 386

I battled with this recently on stackblitz when using it with angular. the issue was pdfmake.vfs on the window object was not being set. so i had to manually set it in the constructor of my pdf service like so.

  constructor() {
    (window as any).pdfMake.vfs = pdfFonts.pdfMake.vfs;
  }

Upvotes: 18

Rijo
Rijo

Reputation: 2718

Following code worked for me:

import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";
pdfMake.vfs = pdfFonts.pdfMake.vfs;

Upvotes: 58

Mauro Candido
Mauro Candido

Reputation: 161

It is just the sequence of the files, add first the pdfmake and then vfs_fonts.

Upvotes: 5

Related Questions