For context I am building a web application that logs hours spent on certain skills or activities and then displays this data back to the user via a bar graph using Chart.js. I am able to successfully display a mock graph when I used the CDNJS however I would like to avoid using CDNJS if possible. I have installed chart.js packages via npm install and double checked installation was successful by verifying it was in the package.json.
This is what my current WORKING mainpage looks like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Main Page</title>
<!-- Reference Chart.js from cdnjs -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js"></script>
</head>
<body>
<h1>Main Page</h1>
<!-- Your main page content here -->
<!-- Canvas element for the chart -->
<canvas id="hoursChart" width="400" height="400"></canvas>
<!-- Button to add logged hours -->
<button onclick="addLoggedHours()">Add Logged Hours</button>
<!-- Button to add new skills -->
<button onclick="addNewSkill()">Add New Skill</button>
<script>
//Function to initialize and update the chart
function updateChart(data) {
var ctx = document.getElementById('hoursChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: [{
label: 'Logged Hours',
data: data.hours,
backgroundColor: 'rgba(75, 192, 192, 0.2)',
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
// Sample data for the chart
var sampleData = {
labels: ['Skill 1', 'Skill 2', 'Skill 3'],
hours: [10, 20, 30] // Sample hours logged for each skill
}
// Call updateChart function with sample data
updateChart(sampleData);
// Need to add function that adds new logged hours
// Need to add function that adds a new skill to graph
</script>
</body>
</html>
Along with my WORKING app.js(only including the relevant portions… can include full app.js file if needed):
const express = require('express');
const exphbs = require('express-handlebars');
const path = require('path');
const app = express();
app.engine('.hbs', exphbs.engine({
extname: '.hbs',
defaultLayout: 'main', // Main layout file
layoutsDir: path.join(__dirname, '..', 'frontend', 'views', 'layouts'),
partialsDir: path.join(__dirname, '..', 'frontend', 'views', 'partials')
}));
app.set('view engine', '.hbs');
app.set('views', path.join(__dirname, '..', 'frontend', 'views'));
// Serve static files (CSS, Javascript, etc.)
app.use(express.static(path.join(__dirname, '..', 'frontend')));
// Define Routes
app.get('/main', (req,res) => {
res.render('mainpage');
});
But I’m wondering if there is anyway to avoid using CDNJS and being able to access the chart.js library directly from the node_modules where it is downloaded.
I’ve tried something like this for the HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Main Page</title>
<!-- Reference Chart.js from node_modules -->
<script src="/node_modules/chart.js/dist/chart.umd.js">
With this addition to the app.js server file:
app.use(express.static(path.join(__dirname, '..', 'node_modules')));
However this does not display the chart and instead gives me these errors in the console:
"GET http://localhost:3000/node_modules/chart.js/dist/chart.umd.js net::ERR_ABORTED 404 (Not Found)"
"Refused to execute script from 'http://localhost:3000/node_modules/chart.js/dist/chart.umd.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled."
"main:45 Uncaught ReferenceError: Chart is not defined"
I’ve checked the file paths multiple times with console logs and consulting ChatGpt to bugfix to make sure they were correct. Even tried feeding it the absolute path instead of the VScode suggested relative path.
Is there a simple fix to this? or should I just default to the CDNJS reference and give up on trying to use the local packages of Chart.js I downloaded from npm.
Authors Note:
Sorry If I’m not describing things correctly or am misunderstanding certain concepts. I’m relatively new to full-stack web development so take it easy on me lol.
2
Answers
I got it to work by referencing this: StackOverflow post about including scripts located inside the node modules folder
and adjusting the top answer by swapping out bootstrap for chart.js.
This is what my script reference in my html looks like now:
and this is how I altered the backend in my app.js file:
I'm not fully sure why it works compared to my other code or if it's even the best approach so any follow-up comments would be appreciated!
You shouldn’t server
node_module
as static because they are specific for nodeJS environment not for browser environmentInstead download the
chart.js
file and serve it as staticuse like this
I’ve assumed you are using static folder, also don’t forget to add the version number in filename