86

I'm trying to follow the instructions to https://stackoverflow.com/a/18633827/2063561, but I still can't get my styles.css to load.

From app.js

app.use(express.static(path.join(__dirname, 'public')));

In my .ejs, I have tried both of these lines

<link rel="stylesheet" type="text/css" href="/css/style.css" />
<link rel="stylesheet" type="text/css" href="/public/css/style.css" />

Neither loads the css. I've gone into the developer's console noticed the type is set to 'text/html' instead of 'text/css'.

My path looks like

.
./app.js
./public
    /css
        /style.css
7
  • 2
    You don't need the closing / for <link> elements. Commented Jul 5, 2014 at 2:12
  • Still didn't work after fixing that. Nice catch. Commented Jul 5, 2014 at 2:19
  • 2
    And you have that express.static middleware line at the very top of the middleware/route stack (e.g. right after you create your app)? Commented Jul 5, 2014 at 3:31
  • 5
    Wow that was actually it. I moved it above app.set('views', __dirname + '/views') and app.set('view engine', 'ejs') and it worked. Thanks! Commented Jul 5, 2014 at 3:45
  • 2
    In the docs: expressjs.com/starter/static-files.html Commented Mar 18, 2015 at 20:41

13 Answers 13

181

Use this in your server.js file

app.use(express.static(__dirname + '/public'));

and add css like

<link rel="stylesheet" type="text/css" href="css/style.css" />

dont need / before css like

<link rel="stylesheet" type="text/css" href="/css/style.css" />
Sign up to request clarification or add additional context in comments.

7 Comments

That'll break for non-root paths though (e.g. hitting /article/edit will result in the browser looking for /article/css/style.css).
I used let path = path.join(__dirname + '/public'); ... you use let path = require('"path"); to use path.join ... joining them as strings on windows did not work
For more information on serving static files (like stylesheets) using Express.
There is a mistake here, you should use the '/' before you path to your .css, otherwise for non-root paths it will not work because the path is not absolute : <link rel="stylesheet" type="text/css" href="/css/style.css" />
I came here looking how to get the images that i was setting as a background to be linked correctly. The same method below can be applied to an 'img' folder which can then be linked to normally if they are both in the public folder. Thanks for a great answer!
|
38

1.Create a new folder named 'public' if none exists.

2.Create a new folder named 'css' under the newly created 'public' folder

3.create your css file under the public/css path

4.On your html link css i.e <link rel="stylesheet" type="text/css" href="/css/style.css">

// note the href uses a slash(/) before and you do not need to include the 'public'

5.On your app.js include : app.use(express.static('public'));

Boom.It works!!

1 Comment

The approach taken in the accepted answer is more reliable than this. See this question. We know the relationship between the public directory and the directory with the script in it. We don't know the relationship between it and the directory the script was invocked from.
15

The custom style sheets that we have are static pages in our local file system. In order for server to serve static files, we have to use,

app.use(express.static("public"));

where,

public is a folder we have to create inside our root directory and it must have other folders like css, images.. etc

The directory structure would look like :

enter image description here

Then in your html file, refer to the style.css as

<link type="text/css" href="css/styles.css" rel="stylesheet">

Comments

10

For NodeJS I would get the file name from the res.url, write the header for the file by getting the extension of the file with path.extname, create a read stream for the file, and pipe the response.

const http = require('http');
const fs = require('fs');
const path = require('path');
const port = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
    let filePath = path.join(
        __dirname,
        "public",
        req.url === "/" ? "index.html" : req.url
    );

    let extName = path.extname(filePath);
    let contentType = 'text/html';

    switch (extName) {
        case '.css':
            contentType = 'text/css';
            break;
        case '.js':
            contentType = 'text/javascript';
            break;
        case '.json':
            contentType = 'application/json';
            break;
        case '.png':
            contentType = 'image/png';
            break;
        case '.jpg':
            contentType = 'image/jpg';
            break;
    }

    console.log(`File path: ${filePath}`);
    console.log(`Content-Type: ${contentType}`)

    res.writeHead(200, {'Content-Type': contentType});

    const readStream = fs.createReadStream(filePath);
    readStream.pipe(res);
});

server.listen(port, (err) => {
    if (err) {
        console.log(`Error: ${err}`)
    } else {
        console.log(`Server listening at port ${port}...`);
    }
});

1 Comment

Very nice, thank you, have been looking for quite some time for something like that.
8

Use in your main .js file:

app.use('/css',express.static(__dirname +'/css'));

use in you main .html file:

<link rel="stylesheet" type="text/css" href="css/style.css" />

The reason you getting an error because you are using a comma instead of a concat + after __dirname.

Comments

4

In your app or server.js file include this line:

app.use(express.static('public'));

In your index.ejs, following line will help you:

<link rel="stylesheet" type="text/css" href="/css/style.css" />

I hope this helps, it did for me!

Comments

4

IMHO answering this question with the use of ExpressJS is to give a superficial answer. I am going to answer the best I can with out the use of any frameworks or modules. The reason this question is often answerd with the use of a framework is becuase it takes away the requirment of understanding 'Hypertext-Transfer-Protocall'.

  1. The first thing that should be pointed out is that this is more a problem surrounding "Hypertext-Transfer-Protocol" than it is Javascript. When request are made the url is sent, aswell as the content-type that is expected.
  2. The second thing to understand is where request come from. Iitialy a person will request a HTML document, but depending on what is written inside the document, the document itsself might make requests of the server, such as: Images, stylesheets and more. This question refers to CSS so we will keep our focus there. In a tag that links a CSS file to an HTML file there are 3 properties. rel="stylesheet" type="text/css" and href="http://localhost/..." for this example we are going to focus on type and href. Type sends a request to the server that lets the server know it is requesting 'text/css', and 'href' is telling it where the request is being made too.

so with that pointed out we now know what information is being sent to the server now we can now seperate css request from html request on our serverside using a bit of javascript.

var http = require('http');
var fs = require('fs');




    function onRequest(request, response){  
        if(request.headers.accept.split(',')[0] == 'text/css') {
             console.log('TRUE');
          
             fs.readFile('index.css', (err, data)=>{
                 response.writeHeader(200, {'Content-Type': 'text/css'});
                 response.write(data);
                 response.end();
             });  
        }

        else {
            console.log('FALSE');    
            
            fs.readFile('index.html', function(err, data){
                response.writeHead(200, {'Content_type': 'text/html'});
                response.write(data);
                response.end();
            });
        };
    };

    http.createServer(onRequest).listen(8888);
    console.log('[SERVER] - Started!');


Here is a quick sample of one way I might seperate request. Now remember this is a quick example that would typically be split accross severfiles, some of which would have functions as dependancys to others, but for the sack of 'all in a nutshell' this is the best I could do. I tested it and it worked. Remember that index.css and index.html can be swapped with any html/css files you want.

4 Comments

I don't understand why you would write an answer in pure node/JavaScript - the question is specifically about express and how to serve files properly using that library. What you say about the basis of the problem being about HTTP is also wrong, it has nothing to do with separating files. Even if the OP followed your advice they still wouldn't know how to serve files on express which is what they wanted to do
@ScottAnderson first of all this question has been edited from the original question, but I would agree that the question as it looks in its contemporary state is directed towards Express, through the author never explicitly states it. When writing this I was hoping to help give an understanding of the mechanics under the hood. I feel that is more help than just giving a couple lines of code to person that's obviously very new to Node. If you don't like it down vote it. If the question hits 0 I will remove it. Every JS framework, no matter the flavor, in essence is Vanilla Flavored.
The question has a code line right up the top which talks about app.set (maybe this wasn't there originally). Don't get me wrong I think that understanding this is useful for web programming, but I just don't see how it's relevant to this question given what OP wrote. Anyways after commenting I saw someone answered very similarly: whilst I can't verify I could say that maybe the original question was quite different. If not, however, then IMHO this falls under 'useful knowledge', not 'relevant information' and should be formalised slightly into a blog or gist and linked in the comments only
Yes, This is what I was hopping to find... thanks
3

I have used the following steps to resolve this problem

  1. create new folder (static) and move all js and css file into this folder.
  2. then add app.use('/static', express.static('static'))
  3. add css like <link rel="stylesheet" type="text/css" href="/static/style.css"/>
  4. restart server to view impact after changes.

Comments

1

Use this in your server.js file

app.use(express.static('public'));

without the directory ( __dirname ) and then within your project folder create a new file and name it public then put all your static files inside it

2 Comments

incomplete answer.
The approach taken in the accepted answer is more reliable than this. See this question. We know the relationship between the public directory and the directory with the script in it. We don't know the relationship between it and the directory the script was invocked from.
1

Its simple if you are using express.static(__dirname + 'public') then don't forget to put a forward slash before public that is express.static(__dirname + '/public') or use express.static('public') its also going to work; and don't change anything in CSS linking.

Comments

1

the order of registering routes is important . register 404 routes after static files.

correct order:

app.use("/admin", admin);
...

app.use(express.static(join(__dirname, "public")));

app.use((req, res) => {
  res.status(404);
  res.send("404");
});

otherwise everything which is not in routes , like css files etc.. , will become 404 .

Comments

0

There is a problem if you use route selectors like "/something" because it will break the css link href if used only "file.css" without the preceding / slash. My approach was:

1- Choose one folder to keep static files as the 'file.css'. Then:

app.use(express.static(__dirname + '/thefolder')); 

2- In the templates, the site root "/" turns it a really static url whatever the route is:

<link href="/file.css" rel="stylesheet">

Now, even if the route is '/something', the css will loaded normally. Without the slash, css wouldn't be found and would get the error message: can't GET /something/file.css.

Comments

-2

The above responses half worked and I'm not why they didn't on my machine but I had to do the following for it work.

  1. Created a directory at the root

    /public/js/

  2. Paste this into your server.js file with name matching the name of directory created above. Note adding /public as the first param

    app.use('/public',express.static('public'));

  3. Finally in the HTML page to which to import the javascript file into,

    <script src="public/js/bundle.js"></script>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.