I have just started using Webpack via a recommendation and am looking for some guidance on how it should be implemented for build and deploy purposes.
I currently have it up and running nicely using webpack-dev-server and some Gulp tasks.
Traditionally I would use Gulp or Grunt to concat files among other things and then use the task runner to copy all my files and assets to a dist or build directory from where I would deploy everything.
At the minute, Webpack does it's thing and builds the bundle file, images etc and then copies them to the build dir, using the [hash].js naming convention.
So my question is, what is the standard practice for then copying over my index.html file and then correctly linking it to the js file to be used in production.
Unless I am completely misunderstanding how Webpack should be used, should there not be some way for me to do this, with the ultimate outcome being me having the ability to navigate to the build dir and see my app up and running as it should be?
I am currently using a plugin to move my index.html. Make sure your webpack.output.publicPath points to your site so it can link images and other resources.
var CopyWebpackPlugin = require('copy-webpack-plugin');
var webpack_config = {
//Other configs here
output: {
publicPath: 'http://localhost/'
},
//Other configs here
plugins:[
new CopyWebpackPlugin([
{from: './index.html', to: './index.html'},
], {
ignore: [
'*.txt',
{glob: '**/*', dot: true}
]
})
],
//Other configs here
}
Related
I've read a bunch of stuff on this, but I still can't seem to serve my files the way I want.
my file structure:
root/
/dist/ <= here is where webpack is putting bundles
/public/ <= here are where all my images are stored
/src/ <= here are my source files
template.html <= some files under src
index.js
webpack.config.js <= files under root
index.html <= html now at root by webpack
My webpack.config has htmlWebpackPlugin configured like so:
new HtmlWebpackPlugin({
"template": "./src/template.html",
"filename": "../index.html", <= moved up to root?
"hash": false,
"inject": true,
"compile": true,
"favicon": false,
"minify": false,
"cache": true,
"showErrors": true,
"chunks": "all",
"excludeChunks": [],
"title": "Webpack App",
"xhtml": true,
"chunksSortMode": 'none' //fixes bug
}),
and my output configured like this:
output: {
filename: '[name].[chunkhash:4].js',
chunkFilename: '[name].[chunkhash:4].js', //name of non-entry chunk files
path: path.resolve(__dirname, 'dist'),
publicPath: "/public" <= not really sure about this
},
So the publicPath, as I understand it, is where the "src" property on image elements will be served from throughout the code, correct? So, in my code, I can just put src='/images....' because '/public' will be prepended. Right?
Also, I read something about 'webpack-dev-server' will serve files from that folder (public) too. Does dev server ever look in the webpack-created dist directiory? Or is that completely separate?
So, as you can see, I moved the index.html up to the root. Not sure if I needed to do that, but I'm trying to figure out how to serve my images that I'm calling from within the html itself.
How can I serve my files easily from within the code '/images/....' and also serve them from the html directly? Should I serve the html from the 'public' folder or will that affect the serving of the dist bundles?
With devServer it might be easiest to just mount your assets-directory., webpack-dev-server uses express behind the scenes so:
const express = require('express');
module.exports = {
...
devServer:{
host: '0.0.0.0',
port: 8080,
before(app) {
app.use('/assets/uploads', express.static(path.resolve('C:\\temp')));
}
}
}
I mean, you'll probably do something similar on your production server anyway.
ie. location /assets/uploads { root /var/www/project; }; in nginx or whatever.
Another method is to use CopyWebPackPlugin:
new CopyWebpackPlugin(
[
{
from: path.resolve(__dirname, 'public'),
to: path.resolve(__dirname, 'dist'),
ignore: [ 'index.html', ... ]
}
]
),
Yet another method could be to add your images to code require('image1.jpg'); somewhere in your entry and add a file-loader and let webpack handle the rest. Webpack is so flexible. If you wonder about the folder-structure, disable webpack-dev-server temporarily so you can see the actual output.
Sorry, I just realized I answered your title question and ignored everything else.
So the publicPath, as I understand it, is where the "src" property on
image elements will be served from throughout the code, correct? So,
in my code, I can just put src='/images....' because '/public' will be
prepended. Right?
No, publicPath is where the static files (production build) on your server are served from, and webpack is going to require all other chunks using that prefix.
Also, I read something about 'webpack-dev-server' will serve files
from that folder (public) too. Does dev server ever look in the
webpack-created dist directiory? Or is that completely separate?
webpack-dev-server servers files from memory, all files compiled.
So, as you can see, I moved the index.html up to the root. Not sure if
I needed to do that, but I'm trying to figure out how to serve my
images that I'm calling from within the html itself.
Not needed.
How can I serve my files easily from within the code '/images/....'
and also serve them from the html directly? Should I serve the html
from the 'public' folder or will that affect the serving of the dist
bundles?
You import your images like: import MyImage from './cat-image.png.
And puts on the src attr in the img tag.
<img src={MyImage} />
Webpack will see the import (you have to have file-loader installed and configured on webpack config file) and will parse it. All those parsed images are going to be outputted to the destination folder (dist or whatever you had configured on your output).
I'm currently tasked with building 2 UI's for a service I've constructed.
The output from both of these UI's will need to end up in the same root folder.
I found the section that names the basic bundles in the "aurelia.json" file, and renamed the bundles created for my project, when built, my project as expected created 2 new bundles in the scripts directory with the new names.
However, upon running my project, I then found that index.html was getting a 404 trying to load the "vendor-bundle" (Which I had renamed to 'service-vendor-bundle').
No problem there, I just edited index.html to reference the new file, and bingo, 404 resolved.
The problem is however, that "service-vendor-bundle" can now not load "service-app-bundle".
I assumed (Probably incorrectly) that, when I renamed the bundles in my aurelia.json file, that the build output would also be configured appropriately to load the files in.
I need to be able to customize this beacuse once the 2 aurelia apps are finished, they will need to share a scripts folder, so I'll need
uione.html to load "scripts\uione-vendor-bundle.js" and "scripts\uione-app-bundle.js"
and I'll need
uitwo.html to load "scripts\uitwo-vendor-bundle.js" and "scripts\uitwo-app-bundle.js"
The final file layout once on the server will look something like the following:
root
uione.html
uitwo.html
scripts
uione-vendor-bundle.js
uione-app-bundle.js
uitwo-vendor-bundle.js
uitwo-app-bundle.js
images
*.png
Both client apps have to be developed separate from each other and be stand alone, so I can't combine them into one app, and I cant put them into seperate folders as the service that will be serving them is a custom in house built service, specifically configured to only serve from a single folder, with a single scripts and images folder.
My aurelia.json file currently looks like this:
.........
"plugins": [
{
"name": "text",
"extensions": [
".html",
".css"
],
"stub": true
}
]
},
"options": {
"minify": "stage & prod",
"sourcemaps": "dev & stage"
},
"bundles": [
{
"name": "uione-app-bundle.js",
"source": [
"[**/*.js]",
"**/*.{css,html}"
]
},
{
"name": "uione-vendor-bundle.js",
"prepend": [
"node_modules/bluebird/js/browser/bluebird.core.js",
"node_modules/requirejs/require.js"
],
..........
and I'm using the Aurelia cli tool (au ...) for my Aurelia based tasks.
Any pointers on how to achieve this would be great.
I think you're on the right track by customizing the bundle names.
What you can do is manually load both the vendor bundle and the app bundle. That way the app modules are already downloaded and ready to use, instead of letting the vendor bundle try to download it manually.
index.html
<body aurelia-app="main">
<script src="scripts/my-special-vendor-bundle.js" data-main="aurelia-bootstrapper"></script>
<script src="scripts/my-special-app-bundle.js"></script>
</body>
I have tested this and it is working fine for me. I am using this manual loading technique in my own project to allow ASP.Net script versioning to provide cache-busting (see my answer here).
I have a project that runs both a build using rollup and a build using browserify for two different outputs. Now, they are both located in the same root dir and I have separate gulp-tasks running for both of them.
My problem is that my browserify task wants a .babelrc file with the following configuration:
{
"presets": ["es2015"]
}
and my rollup task wants this configuration:
{
"presets": ["es2015-rollup"]
}
My question is, can I have two separate .babelrc files and configure which one to use in my gulp and karma config?
I looked around a lot before asking this question and right after I posted I found a possible solution:
gulp.task('rollup', () => {
return gulp.src('src/server/index.js', { read: false })
.pipe(rollup({
plugins: [babel({
presets: ["es2015-rollup"],
babelrc: false
})]
}))
.pipe(gulp.dest('public/'));
});
By configuring one of the tasks to not use the babelrc I could of course configure it myself directly. This isn't a great answer and I would've preferred to just added the name of a babelrc file.
I'm trying to figure out if it is worthwhile moving to webpack, I am leaning towards saying no - figuring I have more important stuff to do - but I would like to see some practical examples of how to make webpack work.
So if I have the following Gulp.js task how would I do them as a webpack task?
gulp.task('subpaths', ['clean_subpaths'],function() {
//Minify and copy all JavaScript (except vendor scripts)
gulp.src(paths.subpath_scripts)
.pipe(fileinclude({
prefix: '##',
basepath: '#file'
}))
.pipe(contextswitch())
.pipe(uglify())
.pipe(strip())
.pipe(rename(function (path) {
path.basename += timestamp;
}))
.pipe(gulp.dest('public/longcache/javascripts/subpath'));
});
So the tasks above do -
include files inside of other files for processing.
run the piped content through my own defined code - I guess in webpack
that would be run my own plugin?
uglify
remove console statements
rename the output file so it has a version.
write out to a specific location
The first item -- include files inside of other files -- is one of webpack's biggest benefits, speaking as someone coming from an all grunt/gulp workflow. Instead of managing dependencies externally (in your build tools), and having to ensure that files are combined correctly based on their runtime dependencies, with webpack your dependencies are part of the codebase, as require() expressions. You write your app as a collection of js modules and each module loads the modules it relies on; webpack understands those dependencies and bundles accordingly. If you're not already writing your js in a modular fashion, it's a big shift, but worth the effort. This is also a reflection of what webpack is meant for -- it's conceptually oriented around building a js application, not bundling some js that your site uses.
Your second item would more likely be a custom loader, which is easier to write than a custom plugin. Webpack is very extendable, throughout, but writing custom integrations is poorly documented.
Webpack's Uglify plugin will also remove console.logs, super easy.
Specifying output details is part of your basic webpack config, just a couple of options to fill in.
I'm using pdf.js in an angular project. Building with gulp in production mode works fine, but the production build produces non-working code that fails silently without and warnings or errors, whatsoever. I never get a viewer canvas.
It turns out the problem lies not with minification, but rather with concatenation.
The dist directory of the pdfjs-dist bower package contains three files:
pdf.js
pdf.worker.js
pdf.combined.js
the bower.json file list pdf.js and pdf.worker.js, but when using gulp bower copy and concatenation you should use pdf.combined.js instead of the other two. Add an override to your projects bower.json
"overrides": {
"pdfjs-dist": {
"main": [
"build/pdf.combined.js"
]
}
}