Copy build files to another project using webpack - javascript

I have two project folders in the same parent folder. One is for front end files (JS, CSS, images etc.) and another is for the backend files. The frontend project uses webpack to build files into a dist folder. The backend project is the one which gets deployed to the server (or run on localhost).
So everytime I make change to a JS or CSS file, I run webpack build, copy the build files from frontend-project/dist folder to backend/frontend/js or backend/frontend/css folder and rerun the backend project.
This is really counter-productive. I want to copy the dist files automatically after build to the backend-project. Is there any way to do it in webpack using a plugin or without using one? I have used gulp for such kind of tasks before, but want to rely solely on webpack for now.
I tried the copy-webpack-plugin, but it doesn't run after the build, thus is not useful for me.

I see several ways how to reach your purposes:
You could specify your backend/frontend/js folder as an output folder for your bundles.
module.exports = {
//...
output: {
path: path.resolve(__dirname, '../backend/frontend')
}
};
If you need two copies of your bundles (one in frontend folder and another in the backend), you can use FileManagerPlugin to copy your bundle files to the backend after finishing of the build.
module.exports = {
//...
plugins: [
new FileManagerPlugin({
events: {
onEnd: {
copy: [
{
source: path.join(__dirname, 'dist'),
destination: path.join(__dirname, '../backend/frontend')
}
]
}
}
})
]
};
If you run build manually after every code change, I think this is unproductive. You can use webpack-dev-server to run build automatically when you develop. It doesn't store bundles in the file system, it keeps them in memory.

Related

How to make webpack-dev-server serve my index.html

I'm trying to get an extremely simple bare-bones TypeScript project setup with Webpack and I'm having an incredibly hard time for some reason.
I followed this guide and everything is working. When I simply run webpack my files will bundle and compile and be outputted into the dist directory. From there I can host them on a local server and it all works fine.
However, I want to avoid having to manually bundle and compile my code every single time I make a change, and I'd like for this to be done automatically each time I save my files. As far as I can tell this is a common use for Webpack and so I'm not sure why I'm having such an incredibly hard time finding any good information on it.
I decided to use the webpack dev server to accomplish this, so I read this tutorial and for the life of me I can't find anybody who explains how to get it to also server my index.html? When I run webpack serve --mode=development all goes well, and when I navigate to the localhost port that I server to I get a 404 error.
One of the "tips" on the previously linked page reads
If you're having trouble, navigating to the /webpack-dev-server route will show where files are served. For example, http://localhost:9000/webpack-dev-server.
When I navigate to localhost:1234/webpack-dev-server it tells me that it's only serving a single file: bundle.js Clearly a JavaScript file alone is not going to work, and I need it to also serve the index.html file that's in my dist directory.
Now, my knowledge here is very limited as this is my first time working with Webpack, but here's all the detail I can give and hopefully it's not accidentally totally unrelated:
Whenever my dev server reloads itself (whenever it's booted up or if a watched file changes while it's running) it only updates the bundle.js file that it's serving. It doesn't update the bundle.js file stored in my dist directory on my hard drive. How can I make it update both?
And also, how do I make the server also serve my index.html file instead of only the bundle.js? Where is it even getting that bundle.js from? Is it compiling all of my code from scratch to create that js file or is it taking that out of the dist directory?
And additionally, am I going about this totally in the wrong way? Where should my index.html even go? I put my TypeScript files into a src directory and they're converted to .js files and moved into my dist directory... Should I also put my index.html inside src or does it belong in dist or somewhere else entirely? When I put index.html in src it doesn't get copied over into dist, it just ignores it completely. If my index.html file doesn't belong in src it must belong in dist, but if it belongs in dist then how can I expect the dev server to find it and serve it along with the other TypeScript files in src? Why can't the dev server just serve everything in dist and automatically compile everything from src into dist? I must be misunderstanding the flow of it all, but I have no idea where to look for an explanation and I've been at this for several hours now.
Just a general explanation of how it all works would be very helpful as well, as I can't find a single article or forum post anywhere that details all the spaghetti going on with Webpack. I've been avoiding bundlers and all this NPM mess for as long as I can because I constantly run into issues like this, but I finally decided to jump in and just push through all the mess and I'm already regretting it. If someone could just point me (and other people having similar problems) to some good resources for learning about all the automagic going on that would be hugely appreciated. The Webpack documentation and guides are very much worthless to a newbie.
My Webpack config file:
const path = require("path");
module.exports = {
entry: "./src/index.ts",
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist")
},
devServer: {
compress: false,
static: false,
client: {
logging: "warn",
overlay: {
errors: true,
warnings: false
},
progress: true
},
port: 1234, host: "0.0.0.0"
}
};
Is your entry set in webpack? So that it is included?
entry: {
main: 'path/to/index.ts'
},
You could also try adding to your index.ts file
require('file-loader?name=[name].[ext]!../index.html');
Or
require("./src/index.html");
// Then In your webpack config file add a loader
loaders : { { test: /\.html/, loader: 'file?name=[name].[ext]' } }
Otherwise you could always copy this file over with webpack copy plugin
{
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
})
]
}
will need to run npm install --save-dev html-webpack-plugin to install it. As well as move your index.html file into your src folder
Please visit localhost:1234/bundle (Where bundle.js is your bundled file) the magichHTML route, which will load the HTML file with the bundled script.

bundling multiple js files

in react using webpack every js files is bundle into a single bundle.js , for my normal html , css, js application for example , i am having 6 libraries. for an example consider
i am using jquery and bootstrap min versions. so if i reference two files the request will be two. so how can i make it into a single file. So there will be a single request.
like when i checked the file size is about in kb's and the request is processed within less that 1 or 2 seconds , like the chrome dev tools shows the time for to load also it parrallely loads the two files.
But how can i bundle the two librarys using webpack and get a single file that i can refer in my application.
i am a beginner to webpack
You need to import them in your entry point file and Webpack will handle the bundling. As you have worked with React, I assume you have basic command line skills.
You can read the Getting Started guide which bundles Lodash like how you are trying to bundle jQuery and Bootstrap.
First of install, ensure that you are installing jQuery, Bootstrap, and any other libraries using npm (or yarn, if you prefer):
# Install Webpack as a dev dependency
npm install webpack webpack-cli --save-dev
# Install dependencies (I've added Popper.js as Bootstrap requires it)
npm install jquery bootstrap popper.js
Create a folder called src and a file inside there called index.js. This is your entry point and Webpack will look for this file unless configured differently. Import the libraries like this:
import $ from 'jquery'
import 'bootstrap'
// Do something with jQuery
$(document).ready(() => console.log('Hello world!'))
Then run Webpack using npx:
npx webpack
A file named main.js should be created in a folder called dist that contains the bundled code. This is your output file. You can use a <script> tag in your HTML file to load this JavaScript:
<!-- assuming your index.html is in the dist folder -->
<script src='main.js'></script>
Once you get here, you can explore more advanced things like importing Bootstrap components individually, minifying code, multiple bundles, transpiling TypeScript, etc.
You will likely need to add a Webpack configuration file very soon as there is only so much that can be done using zero-config mode.
Good practice is to keep two sepearate bundles for the application logic and external libraries and in webpack this can be achieved by the following code,
app.js - appliation index file,
vendors.js - import all external libraries in this file
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
To get a single file, import vendors.js file inside app.js file and give entry key in webpack as
entry: './src/app.js'
Let us assume that you have the files in src directory. You can merge multiple files by specifying them in webpack.config.js to have a single named file as an output. I hope this is what you are looking for.
const path = require('path');
module.exports = {
entry: {
'bundle.js': [
path.resolve(__dirname, 'src/file1.js'),
path.resolve(__dirname, 'src/file2.js')
]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [{
exclude: /node_modules/
}]
}
};
As above, the two files "file1.js" and "file2.js" will be combined into a single file "bundle.js" and stored in "dist" directory.
You can also exclude node_modules by specifying a rule in module object of webpack configuration.

How to prevent Webpack from removing other files in output path?

Let's say I compile some JS assets to dist/static/js:
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
},
Before running npm run build I create one file in /dist/, /static/ and /js/.
After running npm run build this file was removed. The one created in /static/ and /js/ is gone. How can I prevent it?
I'm using Vue.js/Webpack boilerplate:
https://github.com/vuejs-templates/webpack
If you look here:
https://github.com/vuejs-templates/webpack/blob/17ed63b1b3a0eaaebd3f593c08c32107a7cb7e01/template/build/build.js
You can see that a package called rimraf is being imported:
const rm = require('rimraf')
This package is responsible for clearing out your assetsRoot and assetsSubDirectory. This is a good thing because usually when you re-run your build process from nothing, you want a clean slate to begin with.
I would advise you not to disable this but rather put your file in another directory or let your Javascript generate your file since the removal takes places before the compilation.

Webpack less-loader Missing Base Path on Production Build

I've got a vue-js app that uses webpack. Everything works fine in development and test environments, but I'm having trouble getting it to build for production.
I've got background images in the LESS files. The image files are in /static. (I'm not sure whether that's kosher or if they should be in side src/assets.)
At any rate, when the LESS has something like this:
background-url: url("/static/img/foobar/my-image.svg")
Then the compilted CSS will have the same url
background-url: url("/static/img/foobar/my-image.svg")
When the browser loaders, it can't find that imgate file. The browser is attempting to find the file here:
file:///static/img/foobar/my-image.svg
Can anyone recommend a way to prepend the absolute path when the app builds for production?
Do you have your static assets outside of our project directory in /static ?
Otherwise I don't get why your browser is trying to request it from file:///static/img/foobar/my-image.svg
anyway, your static assets should be part of your repo/project. They do not need to be in src directory, a /static folder within the root of your project is just fine.
when you compile your application - let's say into a dist folder - you should copy the images also in that dist folder. In my app I use the copy-webpack-plugin for that task (I have my images in ./public/assets/img/.. and I reference them as /assets/img/..)
const CopyWebpackPlugin = require('copy-webpack-plugin');
...
plugins: [
...
/** copy all files from the public folder to the compilation root */
new CopyWebpackPlugin([{
from: 'public',
to : ''
}]),
...
also you should make sure that you have the file-loader in place for your static assets. I use it like so:
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\??\#?v=[.0-9]+)?$/,
use : 'file-loader?name=assets/[name].[hash].[ext]'
}
I hope this will help you to resolve your problem.
I ended up moving the images into assets/img and then updating my webpack config to specify the directory using publicPath. Here's what it ended up looking like:
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'file-loader',
include: [resolve('src')],
options: {
limit: 10000,
name: '/[name].[hash:7].[ext]',
publicPath: path.resolve(__dirname, 'app')
}

Working project structure that uses grunt.js to combine JavaScript files using RequireJS?

I have some projects that use RequireJS to load individual JavaScript modules in the browser, but I haven't optimized them yet. In both development and production, the app makes a separate request for each JavaScript file, and now I would like to fix that using Grunt.
I have tried to put together a simple project structure to no avail, so I'm wondering if someone can provide a working example for me. My goals are the following:
In development mode, everything works in the browser by issuing a separate request for each required module. No grunt tasks or concatenation are required in development mode.
When I'm ready, I can run a grunt task to optimize (combine) all of the JavaScript files using r.js and test that out locally. Once I'm convinced the optimized application runs correctly, I can deploy it.
Here's a sample structure for the sake of this conversation:
grunt-requirejs-example/
grunt.js
main.js (application entry point)
index.html (references main.js)
lib/ (stuff that main.js depends on)
a.js
b.js
requirejs/
require.js
text.js
build/ (optimized app goes here)
node_modules/ (necessary grunt tasks live here)
Specifically, I'm looking for a working project structure that I can start from. My main questions are:
If this project structure is flawed, what do you recommend?
What exactly needs to be in my grunt.js file, especially to get the r.js optimizer working?
If all of this isn't worth the work and there's a way to use the grunt watch task to automatically build everything in development mode every time I save a file, then I'm all ears. I want to avoid anything that slows down the loop from making a change to seeing it in the browser.
I use the grunt-contrib-requirejs task to build project based on require.js. Install it inside your project directory with:
npm install grunt-contrib-requirejs --save-dev
BTW: --save-dev will add the package to your development dependencies in your package.json. If you're not using a package.json in your project, ignore it.
Load the task in your grunt file with:
grunt.loadNpmTasks('grunt-contrib-requirejs');
And add the configuration to your grunt.initConfig
requirejs: {
production: {
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js",
out: "path/to/optimized.js"
}
}
}
Now you're able to build your require.js stuff into a single file that will be minimized with uglifyjs by running grunt requirejs
You can bundle a set of different tasks into some sort of main task, by adding this to your grunt file
grunt.registerTask('default', ['lint', 'requirejs']);
With this, you can simply type grunt and grunt will automatically run the default task with the two 'subtasks': lint and requirejs.
If you need a special production task: define it like the above
grunt.registerTask('production', ['lint', 'requirejs', 'less', 'copy']);
and run it with
grunt production
If you need different behaviors for 'production' and 'development' inside i.e. the requirejs task, you can use so called targets. In the configuration example above it's already defined as production. You can add another target if you need (BTW, you can define a global config for all targets by adding a options object on the same level)
requirejs: {
// global config
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js"
},
production: {
// overwrites the default config above
options: {
out: "path/to/production.js"
}
},
development: {
// overwrites the default config above
options: {
out: "path/to/development.js",
optimize: none // no minification
}
}
}
Now you can run them both at the same time with grunt requirejs or individually with grunt requirejs:production, or you define them in the different tasks with:
grunt.registerTask('production', ['lint', 'requirejs:production']);
grunt.registerTask('development', ['lint', 'requirejs:development']);
Now to answer your questions:
I would definitely use a subfolder in your project. In my case I use a 'src' folder for development that is build into a 'htdocs' folder for production. The project layout I prefere is:
project/
src/
js/
libs/
jquery.js
...
appname/
a.js
b.js
...
main.js // require.js starter
index.html
...
build/
... //some tmp folder for the build process
htdocs/
... // production build
node_modules/
...
.gitignore
grunt.js
package.json
see above
You can do so, but I wouldn't recommend to add requirejs to the watch task, it's a resource hungry task and it will slow down your machine noticeable.
Last but not least: Be very cautious when playing around with r.js. Especially when you want to optimize the whole project with r.js by adding a modules directive to your config. R.js will delete the output directory without asking. If it happens that it is accidentally configured to be your system root, r.js will erase your HDD. Be warned, I erased my whole htdocs folder permanently some time ago while setting up my grunt task... Always add keepBuildDir:true to your options when playing around with the r.js config.

Categories