When using Webpack, which folder do I have my server statically serve? - javascript

Assuming I want to (my boss is making me) use webpack, and I have a file structure like:
Wherein builds is where webpack outputs the result of bundling/compiling the src folder, how do I then have index.html point to bundle.js if it is present on a server, i.e. which folder do I expose via express.static()? What is the correct "webpack" way to do this with i.e. a simple webpack.config like below? Am I missing something fundamental about how this works? Ideally I'd like to do something like the following in my index.html
<html>
<script src='bundle.js'></script>
<!-- bundle.js spits a bunch of CSS into the html, dynamically builds elements, etc -->
</html>
Or is that not how things are done in webpack?
webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
path: 'builds',
filename: 'bundle.js',
},
module: {
loaders: [
{ test: /\.css$/,
loader: "style!css"
}
]
}
};
I have tried to figure this out via the docs and this oft-linked article.

Since its a good practice to not expose any of your directory structure to end users as it creates a chance for web exploitation, nodejs with express has a mechanism to handle that. What you can do is expose this way your webpack
app.use('/buidscript', express.static(__dirname + '/builds/'));
Then, any browser requests from /buidscript/bundle.js will automatically be fetched from your builds directory.
<script src='/buidscript/bundle.js'></script>
Now you can gather your thoughts around this to make it in whatever way you would like.
For your ideal case which you are looking for
app.use(express.static(__dirname + '/builds'));
Now you can use
<script src='bundle.js'></script>
as any request bundle.js will be searched in exposed static builds directory
Add it to package.json's script
“scripts”: {
“start”: “webpack-dev-server --content-base build/ --inline --hot”,
...
}
// Use it by running
$ npm start
Now this will build your bundle.js before running index.html in development mode.
--content-base build/
will server the static files in your build folder. so then you can make use of bundle.js directly. It will look for any file changes and recompile bundle.js

Related

Why webpack addes a './' to my extern library?

I am using webpack to build both dev and prod code. I added an extern lib correctly in webpack.config.js as below:
externals: {
dagreD3: 'dagre-d3',
}
Of course, I also added the src link to index.html correctly as below:
<script type="text/javascript" src="https://dagrejs.github.io/project/dagre-d3/latest/dagre-d3.min.js"></script>
The dev server works fine and I can use the library without problem. But when I build the prod server, for some reason, a './' was appended to the head of the 'src'. So the source become this:
src="./https://dagrejs.github.io/project/dagre-d3/latest/dagre-d3.min.js"
This breaks the server. I wonder why it is different. Both webpack.prod.config.js and webpack.dev.config.js are loading the same config with the extern:
let baseWebpackConfig = require('./webpack.config');
Thank you so much ~!

Webpack - How to require result file in base html (best practice)

I just started using Webpack for my SPA and I have a question. How do I require the result bundle/file in my HTML? Should I just use the tag or is there a better practice for this?
You can automatically include all JavaScript and CSS bundles using HTML Webpack Plugin.
Example
To install the plugin you need to run npm install html-webpack-plugin --save-dev in your project directory.
In the following example plugin will read source HTML file and automatically append available CSS files in head and all JavaScript bundles just before the end of body. It plays nicely with ExtractTextPlugin. If you have more bundle chunks, they'll be appended appropriately as well.
As a bonus you can use any template engine if you want to dynamically change or generate parts of your HTML file. Out of the box it supports EJS template engine with possibility to use any other via loaders.
var webpack = require("webpack");
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/entry', // Source JavaScript file
output: {
path: './bin/', // Output directory
filename: "./js/bundle.js" // Result JavaScript file
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html', // Source HTML file
filename: './index.html' // Result HTML file
}),
]
};
It's worth noting that HTML Webpack Plugin have a lot of features to play with, including minifying, filtering chunks, adding file hash to URLs to prevent caching... You can learn about those and many more in documentation.
You can look my starter seed with angular2 + webpack. All files has been in build directory(app.js, vendor.js, polyfills.js) + maps
Link to webpack.config.js
Webpack is a module bundler. It will bundle your entire SPA in a single or multiple javascript bundles according to your webpack configuration. Now we need to import these js bundles inside our HTML code and the only way to insert those things in our HTML is to use script tag. So you import them in your html like this :
<script src="bundle.js"></script>
So yes, this is the best practice.

Webpack output file purpose here?

I'm doing the React tutorial (http://www.tutorialspoint.com/reactjs/reactjs_components.htm) and I'm confused as to what webpack entry and output filename do exactly?
In the example they have created a file index.html and App.jsx. However, in the HTML they have "". But no index.js file has been created. Although, the output filename in the webpack.config file is index.js
What I believe is happening, is the entry point is where the server tells client to start out at and the output filename (index.js) is where the server is writing out all of the necessary data that will be sent to the the client... is this right?
Yes that is basically correct you have an entry file where webpack starts to require and compile all other files from and it will export the output/ bundled file to where every you want it to go. Most of the time this compiled and minified depending on which loaders you are using.
entry: 'index.js',
output: {
filename: 'bundle.js',
path: './app/assets'
},

What does "publicPath" in Webpack do?

Webpack docs state that output.publicPath is:
The output.path from the view of the JavaScript.
Could you please elaborate on what this actually means?
I use output.path and output.filename to specify where Webpack should output the result, but I’m not sure what to put in output.publicPath and whether it is required.
module.exports = {
output: {
path: path.resolve("./examples/dist"),
filename: "app.js",
publicPath: "What should I put here?"
}
}
output.path
Local disk directory to store all your output files (Absolute path).
Example: path.join(__dirname, "build/")
Webpack will output everything into localdisk/path-to-your-project/build/
output.publicPath
Where you uploaded your bundled files. (absolute path, or relative to main HTML file)
Example: /assets/
Assumed you deployed the app at server root http://server/.
By using /assets/, the app will find webpack assets at: http://server/assets/. Under the hood, every urls that webpack encounters will be re-written to begin with "/assets/".
src="picture.jpg" Re-writes ➡ src="/assets/picture.jpg"
Accessed by: (http://server/assets/picture.jpg)
src="/img/picture.jpg" Re-writes ➡ src="/assets/img/picture.jpg"
Accessed by: (http://server/assets/img/picture.jpg)
When executed in the browser, webpack needs to know where you'll host the generated bundle. Thus it is able to request additional chunks (when using code splitting) or referenced files loaded via the file-loader or url-loader respectively.
For example: If you configure your http server to host the generated bundle under /assets/ you should write: publicPath: "/assets/"
the publicPath is just used for dev purpose, I was confused at first time I saw this config property, but it makes sense now that I've used webpack for a while
suppose you put all your js source file under src folder, and you config your webpack to build the source file to dist folder with output.path.
But you want to serve your static assets under a more meaningful location like webroot/public/assets, this time you can use out.publicPath='/webroot/public/assets', so that in your html, you can reference your js with <script src="/webroot/public/assets/bundle.js"></script>.
when you request webroot/public/assets/bundle.js the webpack-dev-server will find the js under the dist folder
Update:
thanks for Charlie Martin to correct my answer
original: the publicPath is just used for dev purpose, this is not just for dev purpose
No, this option is useful in the dev server, but its intention is for asynchronously loading script bundles in production. Say you have a very large single page application (for example Facebook). Facebook wouldn't want to serve all of its javascript every time you load the homepage, so it serves only whats needed on the homepage. Then, when you go to your profile, it loads some more javascript for that page with ajax. This option tells it where on your server to load that bundle from
filename specifies the name of file into which all your bundled code is going to get accumulated after going through build step.
path specifies the output directory where the app.js(filename) is going to get saved in the disk. If there is no output directory, webpack is going to create that directory for you.
for example:
module.exports = {
output: {
path: path.resolve("./examples/dist"),
filename: "app.js"
}
}
This will create a directory myproject/examples/dist and under that directory it creates app.js, /myproject/examples/dist/app.js. After building, you can browse to myproject/examples/dist/app.js to see the bundled code
publicPath: "What should I put here?"
publicPath specifies the virtual directory in web server from where bundled file, app.js is going to get served up from. Keep in mind, the word server when using publicPath can be either webpack-dev-server or express server or other server that you can use with webpack.
for example
module.exports = {
output: {
path: path.resolve("./examples/dist"),
filename: "app.js",
publicPath: path.resolve("/public/assets/js")
}
}
this configuration tells webpack to bundle all your js files into examples/dist/app.js and write into that file.
publicPath tells webpack-dev-server or express server to serve this bundled file ie examples/dist/app.js from specified virtual location in server ie /public/assets/js. So in your html file, you have to reference this file as
<script src="public/assets/js/app.js"></script>
So in summary, publicPath is like mapping between virtual directory in your server and output directory specified by output.path configuration, Whenever request for file public/assets/js/app.js comes, /examples/dist/app.js file will be served
You can use publicPath to point to the location where you want webpack-dev-server to serve its "virtual" files. The publicPath option will be the same location of the content-build option for webpack-dev-server. webpack-dev-server creates virtual files that it will use when you start it. These virtual files resemble the actual bundled files webpack creates. Basically you will want the --content-base option to point to the directory your index.html is in. Here is an example setup:
//application directory structure
/app/
/build/
/build/index.html
/webpack.config.js
//webpack.config.js
var path = require("path");
module.exports = {
...
output: {
path: path.resolve(__dirname, "build"),
publicPath: "/assets/",
filename: "bundle.js"
}
};
//index.html
<!DOCTYPE>
<html>
...
<script src="assets/bundle.js"></script>
</html>
//starting a webpack-dev-server from the command line
$ webpack-dev-server --content-base build
webpack-dev-server has created a virtual assets folder along with a virtual bundle.js file that it refers to. You can test this by going to localhost:8080/assets/bundle.js then check in your application for these files. They are only generated when you run the webpack-dev-server.
in my case,
i have a cdn,and i am going to place all my processed static files (js,imgs,fonts...) into my cdn,suppose the url is http://my.cdn.com/
so if there is a js file which is the orginal refer url in html is './js/my.js'
it should became http://my.cdn.com/js/my.js in production environment
in that case,what i need to do is just set publicpath equals http://my.cdn.com/
and webpack will automatic add that prefix
There are lots of good answers here, so I'll focus on output.publicPath: 'auto'.
Say when you build your project you get the next folder structure:
dist/blog/index.html
dist/app.js
dist/app.css
dist/index.html
In this case, both our index.html files have to have a correct path to our app.js and app.css (next - assets). Let's consider the next scenarios:
publicPath: '' or publicPath: '/':
When hosted on a server both point to the root of the website (ex. https://localhost:8080/), so everything works fine.
But should you try to open them locally, blog/index.html won't have a correct path to the assets. In case of publicPath: '' assets will be searched in the blog/ folder since that's where the relative path is pointing to. index.html still has the correct path to assets.
And in case of publicPath: '/', / points to the root of the filesystem, so neither of our index.html files will have a correct path to assets.
publicPath: 'auto':
In this case, both our index.html files will have relative paths to the assets. So, blog/index.html will be pointing to ../app.css, and index.html will be pointing to app.css.
The webpack2 documentation explains this in a much cleaner way:
https://webpack.js.org/guides/public-path/#use-cases
webpack has a highly useful configuration that let you specify the base path for all the assets on your application. It's called publicPath.
publicPath is used by webpack for the replacing relative path defined in your css for refering image and font file.

Wildcard selectors in css path for grunt-contrib-compass

I'm trying to use grunt-contrib-compass for an AngularJS project with multiple app folders. Here is my basic directory structure:
/root
/appA
/appB
...
/appX
/public
/modules
/moduleName
/css
/sass
gruntfile.js is stored in /root
My compass task is set up as follows:
compass: {
dev: {
options: {
cssDir: 'app*/public/modules/**/css',
sassDir: 'app*/public/modules/**/sass',
outputStyle: 'compressed'
}
}
}
Note the wildcard selectors (*) in "cssDir" and "sassDir".
When this task runs, it successfully finds the .scss files in the directory specified for "sass". However, upon creating the .css files, it creates a new folder structure in /root like so:
/root
/app*
/public
/modules
/**
/css
The "css" folder is left empty and the actual .css file is saved in the same directory as my .scss files.
As an example, this is the terminal output for one of the .scss files when the compass task is run:
>> File "appStudentHousing/public/modules/studentHousingHome/sass/styles.scss" changed.
Running "compass:dev" (compass) task
directory appStudentHousing/public/modules/studentHousingHome/sass
write appStudentHousing/public/modules/studentHousingHome/sass/styles.css (0.003s)
It appears that the task recognizes wildcard selectors in the "sassDir" option, but it does not recognize them in the "cssDir" option. It creates a blank folder structure with the asterisks in the actual folder name, and then for some reason it saves the output .css file in the same folder as the .scss file.
Thanks much for any insight you can provide.
My comments converted into an answer:
Currently, the compass grunt plugin can only process single directories per target, thus no globbing that would match with multiple directories.
To circumvent this limitation, you always have the ability to create mutiple targets inside your compass task (Grunt functionality). A target is a subdivision of a task and can be used to setup different execution scenarios.
Two different targets for the compass plugin could look something similar to this:
compass: {
dev: {
options: {
cssDir: 'app/dev/modules/css',
sassDir: 'app/dev/modules/sass',
outputStyle: 'compressed'
}
},
live: {
options: {
cssDir: 'app/live/modules/css',
sassDir: 'app/live/modules/sass',
outputStyle: 'compressed'
}
}
}
This would give you two targets, dev and live, which specify different options. To execute each target individually, you simply call them on your command-line as follows:
$ grunt compass:dev
$ grunt compass:live
The naming of a target is totally up to you, there are no strict conventions to follow. If you have a single target for your task, then running the task like so:
$ grunt compass
Executes the single target. You do not need to explicitly specify it. However, if you have multiple targets in your task, then Grunt shall execute all of them in order when running with the above command.
And, as you have seen yourself, the official Grunt documentation gives you more detailed info regarding tasks and targets.

Categories

Resources