Как загрузить внешний CSS-файл с помощью Pug

#javascript #css #node.js #express #pug

Вопрос:

Я пытаюсь загрузить файл css и изображение в свой файл pug, но ни один из них не загружается. Такое чувство, что я перепробовал все, что мог найти, но не нашел решения. У меня есть css и изображение в общей папке, которая установлена как статическая с помощью express. Я ценю любую помощь, которую могу получить.

Структура папок выглядит следующим образом:

 server.js
views
  checklist.pug
routes
  checklist.js
public
  images
    logo.png
  stylesheets
    checklist.css
pdfs
 

server.js

 require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();

const checklists = require('./routes/checklists');

const port = 3000;

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// View engine
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, 'public')));

// Routes
app.use('/checklists', checklists);

app.listen(port, () => {
    console.log(`Server started on port ${port}...`);
});
 

контрольный список.мопс

 html(lang='en')
    head
        link(href='stylesheets/checklist.css' rel='stylesheet')
        link(rel='preconnect' href='https://fonts.googleapis.com')
        link(rel='preconnect' href='https://fonts.gstatic.com' crossorigin)
        link(href='https://fonts.googleapis.com/css2?family=Robotoamp;display=swap' rel='stylesheet')
    body 

        div(class='checklist-title')
            img(src='images/logo.png' alt='Logo...')
 

checklist.js

 const express = require('express');
const aws = require('aws-sdk');
const { v4 } = require('uuid');
const puppeteer = require('puppeteer');
const pug = require('pug');

const dynamodb_config = require('../config/dynamodb/dynamo_config');
aws.config.update(dynamodb_config);
const { validateChecklist } = require('../middleware/validation');
const authenticateToken = require('../middleware/authenticateToken');

const router = express.Router();
const docClient = new aws.DynamoDB.DocumentClient();

const TABLE_NAME = 'Checklists';

// Generate html from checklist object, convert to pdf and send in response
router.get('/:id/pdf', authenticateToken, (req, res) => {
    // Get the checklist and make sure the user owns it
    const params = {
        TableName: TABLE_NAME,
        Key: {
            id: req.params.id
        }
    }
    docClient.get(params, async (err, data) => {
        if (err) {
            console.error(err);
            res.status(500);
            res.json({
                error: err
            });
        }
        else {
            // Check that an item was found
            if (typeof data.Item != 'undefined') {
                // An item was found
                // Check that the user who sent the request is the owner of the item
                if (req.username == data.Item.createdBy) {
                    // CODE TO GENERATE CHECKLIST HERE
                    try {
                        const checklist = {
                            checklist: data.Item
                        }
                        // render html
                        const compiledFunction = pug.compileFile('views/checklist.pug');
                        const htmlContent = compiledFunction(checklist);

                        // convert html to pdf and save file
                        const browser = await puppeteer.launch();
                        const page = await browser.newPage();
                        await page.setContent(htmlContent, { waitUntil: 'networkidle2' });
                        await page.pdf({ path: `pdfs/${req.username}.pdf`, printBackground: true });
                        await browser.close();

                        res.status(200);
                        res.json({
                            message: 'success'
                        });
                    }
                    catch (err) {
                        console.error(err);
                    }
                }
                else {
                    // User does not own the item
                    console.error('You are not authorized to access that item');
                    res.status(403);
                    res.json({
                        error: 'You are not authorized to access that item'
                    });
                }
            }
            else {
                // No item was found
                console.error(`A checklist with id ${req.params.id} could not be found`);
                res.status(404);
                res.json({
                    error: `A checklist with id ${req.params.id} could not be found`
                });
            }
        }
    });
});

module.exports = router;
 

Комментарии:

1. link(href="/stylesheets/checklist.css" rel="stylesheet") и img(src="/images/logo.png" routes Папка не упоминается в вашей структуре папок. checklist.js не отображается.

2. Спасибо @OldGeezer, К сожалению, эти изменения в путях не решили проблему. Извините за недостающую информацию, я обновил вопрос со структурой папок маршрутов и добавил соответствующую информацию из checklist.js. Дай мне знать, что ты думаешь. Я ценю вашу помощь.

3. Я думаю, что проблема может быть в том, в puppeteer чем у меня нет опыта. Похоже, что он создает html-страницу из некоторого содержимого файла, а не из веб-URL. Поэтому пути для вложенных папок изображений и таблиц стилей должны быть относительно папки по умолчанию, которая применяется к браузеру при page.newPage() вызове. Вы можете попробовать поэкспериментировать, чтобы найти это место, если его нет в puppeteer документации.

4. То, что делает код, сначала генерирует html из файла pug и моего объекта базы данных, затем загружает этот html в puppeteer (браузер без головы), а затем я, по сути, печатаю эту страницу браузера в pdf. Папка pdf находится в корневой папке проекта. Я обновил свой вопрос, чтобы показать это. Хотя, насколько я понимаю, это ничего не должно изменить. Я думаю, что ваша точка зрения об относительном пути для браузера может быть на что-то похожа, но не сразу понятно, как я мог бы это проверить.

Ответ №1:

Таким образом, проблема в конечном итоге оказалась в том, что кукольник в конце концов, как сказал @OldGeezer. Поскольку я использовал функцию page.setContent() от puppeteer для загрузки html-содержимого непосредственно в браузер вместо указания пути к html-файлу, ни один из относительных путей к моему изображению или css не работал. В итоге я решил эту проблему, используя функцию page.goto(путь) в puppeteer для загрузки пустого html-файла, который я создал в общей папке, а затем используя функцию page.setContent() для загрузки нужного мне html. Это позволило браузеру находиться в нужном каталоге для загрузки внешних файлов по их относительным путям.

 server.js
views
  checklist.pug
routes
  checklist.js
public
  empty.html
  images
    logo.png
  stylesheets
    checklist.css
pdfs
 

checklist.js

 const express = require('express');
const aws = require('aws-sdk');
const { v4 } = require('uuid');
const puppeteer = require('puppeteer');
const pug = require('pug');

const dynamodb_config = require('../config/dynamodb/dynamo_config');
aws.config.update(dynamodb_config);
const { validateChecklist } = require('../middleware/validation');
const authenticateToken = require('../middleware/authenticateToken');

const router = express.Router();
const docClient = new aws.DynamoDB.DocumentClient();

const TABLE_NAME = 'Checklists';

// Generate html from checklist object, convert to pdf and send in response
router.get('/:id/pdf', authenticateToken, (req, res) => {
    // Get the checklist and make sure the user owns it
    const params = {
        TableName: TABLE_NAME,
        Key: {
            id: req.params.id
        }
    }
    docClient.get(params, async (err, data) => {
        if (err) {
            console.error(err);
            res.status(500);
            res.json({
                error: err
            });
        }
        else {
            // Check that an item was found
            if (typeof data.Item != 'undefined') {
                // An item was found
                // Check that the user who sent the request is the owner of the item
                if (req.username == data.Item.createdBy) {
                    // CODE TO GENERATE CHECKLIST HERE
                    try {
                        const checklist = {
                            checklist: data.Item
                        }
                        // render html
                        const compiledFunction = pug.compileFile('views/checklist.pug');
                        const htmlContent = compiledFunction(checklist);

                        // convert html to pdf and save file
                        const browser = await puppeteer.launch();
                        const page = await browser.newPage();

                        // go to empty html file
                        await page.goto('file://'   __dirname   '/../public/empty.html');

                        await page.setContent(htmlContent, { waitUntil: 'networkidle2' });
                        await page.pdf({ path: `pdfs/${req.username}.pdf`, printBackground: true });
                        await browser.close();

                        res.status(200);
                        res.json({
                            message: 'success'
                        });
                    }
                    catch (err) {
                        console.error(err);
                    }
                }
                else {
                    // User does not own the item
                    console.error('You are not authorized to access that item');
                    res.status(403);
                    res.json({
                        error: 'You are not authorized to access that item'
                    });
                }
            }
            else {
                // No item was found
                console.error(`A checklist with id ${req.params.id} could not be found`);
                res.status(404);
                res.json({
                    error: `A checklist with id ${req.params.id} could not be found`
                });
            }
        }
    });
});

module.exports = router;