71

I have a directory structure

projectName
    | - bower_components/
    | - public/
        | - css
        | - js
        | - index.html
    | - Gruntfile.js
    | - package.json
    | - bower.json
    | - app.js

I would like to start my app and serve index.html with node. So in app.js I have:

var express = require('express');
var port = process.env.PORT || 3000;
var app = express();

app.configure(function(){
    // Serve up content from public directory
    app.use(express.static(__dirname + '/public'));
    app.use(app.router);
    app.use(express.logger()); 
});

app.listen(port, function(){
    console.log('Express server listening on port ' + port);
});

At the bottom of index.html I have:

<script src="../bower_components/jquery/jquery.js"></script>
<script src="../bower_components/d3/d3.js"></script>
<script src="../bower_components/bootstrap/dist/js/bootstrap.js"></script>
<script src="bower_components/spin.js/spin.js"></script>
<script src="bower_components/mustache/mustache.js"></script>

When I start the server, index.html shows up but none of the above libraries load. I get the error (404):

GET http://localhost:3000/bower_components/jquery/jquery.js 404 (Not Found) localhost/:32
GET http://localhost:3000/bower_components/d3/d3.js 404 (Not Found) localhost/:33
GET http://localhost:3000/bower_components/bootstrap/dist/js/bootstrap.js 404 (Not Found) localhost/:34
GET http://localhost:3000/bower_components/spin.js/spin.js 404 (Not Found) localhost/:35
GET http://localhost:3000/bower_components/mustache/mustache.js 404 (Not Found) 

How can I serve the files from bower_components?

Amol M Kulkarni
  • 21,143
  • 34
  • 120
  • 164
Connor Leech
  • 18,052
  • 30
  • 105
  • 150
  • See also my similar question (answered), maybe it may help: http://stackoverflow.com/questions/23933621/bower-components-doesnt-load-dependencies-on-the-page – Green Jun 05 '14 at 10:44
  • I have a question. Does `package.json` and `bower.json` conflicts with each others? For fields such as name, version, maybe even dependencies with the same package of different version. what do you put in package.json and what do you put in bower.json? – Nam Thai Aug 05 '15 at 00:01
  • `package.json` is for npm dependencies (many times that is server side or build system requirements) where `bower.json` is only for client side dependencies like bootstrap, angular or jquery. They do not conflict with each other – Connor Leech Aug 05 '15 at 03:01

7 Answers7

194

I use this setup:

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

So any Bower components are loaded from HTML like this:

<script src="/bower_components/..."></script>

And any other client-side JS/CSS (in public/) are loaded like this:

<script src="/js/..."></script>
robertklep
  • 198,204
  • 35
  • 394
  • 381
  • I found why it doesn't work http://stackoverflow.com/questions/23933621/bower-components-doesnt-load-dependencies-on-the-page – Green Jun 05 '14 at 10:46
  • 12
    answer should now use path.join(__dirname, '/bower_components') – Warren Dec 09 '14 at 16:23
  • I used Yeoman to generate bootstrap and express. I had to add `app.use('/bower_components', express.static(config.root + '/bower_components'));` to the /config/express.js file. Notice the *config.root* instead of __dirname – kingdango Mar 07 '15 at 21:18
  • I have a question. The above project have both `package.json` and `bower.json`. Do those conflict with each others? For fields such as name, version, maybe even dependencies with the same package of different version. what should be in package.json and what should be in bower.json? – Nam Thai Aug 05 '15 at 00:03
  • @NickyThai generally speaking, `bower.json` is meant for client-side dependencies, `package.json` for server-side dependencies. – robertklep Aug 05 '15 at 06:32
  • `path.join(__dirname, 'bower_components')` don't need the first slash. you use the path library so it uses the system path separator. – Mustafa Oct 23 '15 at 12:55
  • [2015] this worked for me : app.use("/bower_components", express.static(path.join(__dirname, 'bower_components'))); and in the view it doesn't matter what you write (./bower_components or ../bower_components). All these worked for me : – Bardelman Oct 31 '15 at 09:37
  • on windows system, I am able to use assets files from other folder using same process only not working with "bower_components" folder. Help me to fix it. – Sach Aug 03 '16 at 09:35
  • Why do we need to do this for bower_components but not for other directory such as css js img? I can't find any documentation – TSR Jan 18 '18 at 16:21
  • @TSR _strictly_ speaking it's not necessary, because you could also do this: `app.use(express.static(__dirname))`. However, this is (very) insecure because it exposes _all_ files in `__dirname` through the static middleware. That's why you want to add an explicit path prefix (the first argument for `app.use()`), and use `__dirname + '/bower_components'` as static directory. – robertklep Jan 18 '18 at 16:28
  • @robertklep No, my question was about what you mentioned here: "And any other client-side JS/CSS (in public/) are loaded like this:" For client-side JS/CSS, why I don't need to do something like this: app.use('/js', express.static( path.join(__dirname, '/js'))); or this: app.use('/css', express.static( path.join(__dirname, '/css'))); I can't find a documentaton about that – TSR Jan 18 '18 at 16:33
  • @TSR you can still do that, but it's not necessary because the `public/` directory is meant to be exposed entirely. – robertklep Jan 18 '18 at 19:40
8

You should use

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

Note the usage of (path.join) which is different from @robertklep answer

Here is a note from Another SO questions which according to me captures it very well

path.join will take care of unneccessary delimiters, that may occur if the given pathes come from unknown sources (eg. user input, 3rd party APIs etc.).

So path.join('a/','b') path.join('a/','/b'), path.join('a','b') and path.join('a','/b') will all give a/b.

Without using it, you usually would make expectations about the start and end of the pathes joined, knowing they only have no or one slash.

Community
  • 1
  • 1
Abhijit Mazumder
  • 8,641
  • 7
  • 36
  • 44
  • 1
    `path.join` should not contain concatenation with `+` operator, it should be comma `,` instead – Warlock Jun 13 '15 at 17:41
  • I have tried with both + and , but not work on windows system. But I am able to use assets files from other folder using same process only not working with "bower_components" folder. Help me to fix it. – Sach Aug 03 '16 at 09:33
  • @robertklep Why do we need to do this for bower_components but not for other directory such as css js img? I can't find any documentation – TSR Jan 18 '18 at 16:21
6

Bower can be configured using JSON in a .bowerrc file.

Add an .bowerrc file with the following contents at the root of your project with the contents.

{
  "directory": "public/bower_components"
}

This will place the bower components your are refering to in the correct library and you will not need the extract static directory in express.

Jonathan Lam
  • 16,831
  • 17
  • 68
  • 94
Arthur Anderson
  • 152
  • 2
  • 8
1

Change your directory structure to :

projectName

    | - public/
        | - bower_components/
        | - css
        | - js
        | - index.html
    | - Gruntfile.js
    | - package.json
    | - bower.json
    | - app.js

And in index.html do following changes:

<script src="../public/bower_components/jquery/jquery.js"></script>
<script src="../public/bower_components/d3/d3.js"></script>
<script src="../public/bower_components/bootstrap/dist/js/bootstrap.js"></script>
<script src="public/bower_components/spin.js/spin.js"></script>
<script src="public/bower_components/mustache/mustache.js"></script>


Or another way is to turn your bower_components folder to severed as static content. (you can inject static middleware multiple times for express)
Add the following in app congfig to express. Then your config code looks like:
var express = require('express');
var port = process.env.PORT || 3000;
var app = express();

app.configure(function(){
    // Serve up content from public directory
    app.use(express.static(__dirname + '/public'));
    app.use(express.static(__dirname + '/bower_components'));
    app.use(app.router);
    app.use(express.logger()); 
});

app.listen(port, function(){
    console.log('Express server listening on port ' + port);
});

And in this case your directory structure remains the same. Hope this helps.
Happy coding.. :)

Amol M Kulkarni
  • 21,143
  • 34
  • 120
  • 164
  • 2
    My gut feeling tells me this was down-voted because if you move the bower_components directory manually under another, you lose some of the power of a package manager. – webkenny Jan 03 '15 at 14:32
  • 2
    You can configure bower to place its `bower_components` folder within the `public` folder by using a `.bowerrc` file, as in [this example with express and grunt](https://github.com/blai/grunt-express-angular-example). If I'm using Grunt, I want to configure my server's static file directories in my Gruntfile, and I can't figure out how to do it with `grunt-express`, which is what I'm using. So my solution was to just move the folder. – Matthias Apr 08 '15 at 17:40
  • 1
    I almost downvoted your answer as a knee-jerk reaction. I was thinking that moving the `bower_components` folder was an antipattern. But I couldn't think of any good reasons against it, and it looks like an easy solution. – Matthias Apr 08 '15 at 17:46
0

I'm using:

$ npm -version && node -v
2.11.3
v0.12.7

And my app.js has this defining bower_components as a static path:

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

In my Jade template, I reference jquery and bootstrap like so:

doctype html
html
    head
        title= title
        link(href='bootstrap/dist/css/bootstrap.min.css', rel='stylesheet')
        link(href='bootstrap/dist/css/bootstrap-theme.min.css', rel='stylesheet')
    body
        block content

    script(type='text/javascript', src='jquery/dist/jquery.js')
    script(type='text/javascript', src='bootstrap/dist/js/bootstrap.js')

I'm running Windows 7 (x64).

Hope this helps someone.

FilmiHero
  • 2,306
  • 7
  • 31
  • 46
0

Had the same problem after moving bower_components into another folder. This has helped me to understand what was going on. The docs were useful: https://github.com/expressjs/serve-static

and I put this code into my node/express app.js file:

console.log('DIRNAME:', __dirname, 'JOINED:', path.join(__dirname, '../../bower_components'));

This is from index.html

<script src="/bower_components/jquery/dist/jquery.js"></script>
<script src="/bower_components/angular/angular.js"></script>

and in app.js

app.use('/bower_components', express.static(path.join(__dirname, '../../bower_components')))

which is a correct path in my case.

MojoDBA
  • 118
  • 7
0

This also works for me:

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

Make sure you have reset your local server or make sure you are running nodemon for seeing your changes!