why we need to exclude node_modules in webpack? - javascript

below is a webpack config file:
module.exports = {
mode: "development",
entry: "./src/index.ts",
output: { filename: "bundle.js" },
resolve: { extensions: [".ts"] },
module: {
rules: [
{ test: /\.ts/, use: "ts-loader", exclude: /node_modules/ }
}
]
}
};
I don't understand why we need to exclude node_modules when dealing with typescript files? Below is my points:
1-Firstly, nearly all packages are written in js not in ts, it is not going to harm if we include node_modules.
2-If we are referencing a package that is written in ts, we definitely want ts code to be compiled to js code, then we have to include node_modules to make sure everything works, don't we?

1-Firstly, nearly all packages are written in js not in ts, it is not going to harm if we include node_modules.
Excluding node_modules at the transpiling stage increases performance which could otherwise get a hit.
If we are referencing a package that is written in ts, we definitely want ts code to be compiled to js code, then we have to include node_modules to make sure everything works, don't we?
Yes, and then is the key here. Excluding node_modules at the transpiling stage doesn't prevent webpack from using its content at the bundling stage.

Related

what's the workflow of style-loader and css-loader

I'm new to webpack, still a little bit confused that how webpack cooperate with loaders. Let's we have below typescript file index.ts:
//index.ts
import "bootstrap/dist/css/bootstrap.css";
...
// typescript code
and below is the webpack config file:
module.exports = {
mode: "development",
entry: "./src/index.ts",
output: { filename: "bundle.js" },
resolve: { extensions: [".ts", ".js", ".css"] },
module: {
rules: [
{ test: /\.ts/, use: "ts-loader", exclude: /node_modules/ },
{ test: /\.css$/, use: ["style-loader", "css-loader"] }
]
}
};
Below is my personal thought on how webpack works with loaders, please correct me if I'm wrong:
Step 1-Webpack encounter index.ts, so it passes this file to ts-loader, and ts-loader read the file and pass it to ts compiler, ts compiler generates js code file index.js and pass back to ts-loader, then ts-loader passes index.js back to webpack.
Step 2- Webpack reads index.js and needs to resolve the css file, so Webpack passes the task to css-loader, so css-loader reads the css file as a long long string, then passes the task to style-loader, which creates js code that can be embedded in tags in the index.html file.
Step 3- bundle.js is ready, and client sends a http request to get index.html, and the bundle.js is fetched and create a <style> tags to include all css styles.
Is my above understanding correct? If yes, below is my questions:
Q1-after style-loader generates js code, does it pass those js code back to css-loader, then css-loader passes received js code to webpack? or style-loader pass generated js code to webpack directly?
Q2- in the webpack config file:
...
{ test: /\.css$/, use: ["style-loader", "css-loader"] }
...
it seems that the style-loader is used first, then css-loader steps in( I have tried this approach, it worked, not sure why it worked)
isn't that the css-loader should start to work first then style-loader as:
...
{ test: /\.css$/, use: ["css-loader", "style-loader"] }
...
Is my above understanding correct?
Yes
Q1-after style-loader generates js code, does it pass those js code back to css-loader, then css-loader passes received js code to webpack? or style-loader pass generated js code to webpack directly?
Answer: style-loader pass generated js code to webpack directly
Q2 it seems that the style-loader is used first, then css-loader steps in,
It can seem wrong. But its one of those things you need to read the docs for. The last thing to process it is mentioned at the top of the array. Personally I don't think the other way around would be any more intuitive.

Webpack - Bundle multiple/different versions of .css files

I would like to make my bundled .css file being generated by Webpack more configurable, so I can output different 'versions' - based on the same .css file - to make the life of developers working on my project in the future easier.
I would like to have the following steps:
Concat of all SCSS into CSS (bundle.css)
Minimize output of step 1 (bundle.min.css)
Embed all images from step 2 (bundle.b64.min.css)
Embed all fonts from step 3 (bundle.bs64.fonts.min.css)
In the end - after my build process -, I would have 4 distinct files in my dist folder. Would that me possible?
The way I'm currently doing it, I run a different script for each step - deletes dist folder, goes through project, produces the output. I would like to have a single script that does all of it at once without having to go through my project 4 times.
I kind of found a solution for it here:
Webpack Extract-Text-Plugin Output Multiple CSS Files (Both Minified and Not Minified)
But, for my specific case, I would have to return 4 different configurations in a array instead of a single object.
Ok so based on our comment conversation i'm gonna give you a workflow of steps 1-4, but with regular assets handling, not a bundling of assets (which i haven't heard of but maybe someone else can elaborate there).
So the steps:
bundle all scss files into 1 bundle.css
make sure this bundle is minified
add assets management to build for images
add assets management to build for fonts
The important things:
This workflow is basically a built by configuration. configuring the npm scripts with the package.json file, and configuring webpack with config.webpack.js. This will allow you to simply run 1 command to build your project: npm run build. note: For simplicity's sake i am going to ignore production/development/etc environments and focus on a single environment.
package.json:
This is used to set up the command that will actually run when you input npm run build in the terminal (from the project dir of course).
since we are avoiding different environments for now and as you are not using Typescript this is a very simple configuraton:
"scripts": {
"build": "webpack",
},
that's all you have to add. It sound's stupid now but when the project will get more complex you are going to like those scripts so better start off making them already.
webpack.config.js:
The major lifting will be made in this configuration file. This basically tells webpack what to do when you run it (which is what npm run build is doing).
first off let's install some plugins:
npm install --save-dev file-loader
npm install --save-dev html-webpack-plugin
npm install --save-dev mini-css-extract-plugin
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production',
devtool: 'source-map'
entry: './client/src/app.jsx',
output: {
path: path.join(__dirname, 'client/dist/public'),
filename: 'bundle.[hash].js'
},
module: {
rules: [
{
test: /\.s?css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: false
}
},
'css-loader',
'sass-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
]
},
resolve: {
extensions: ['.js', '.json', '.jsx']
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './client/src/index_template.html'
}),
new MiniCssExtractPlugin({
filename: 'style.[hash].css',
chunkFilename: '[id].[hash].css'
}),
]
};
Notice i've added the htmlWebpackPlugin because it makes it easier to reference the correct hashed bundles automatically. Also I've assumed the app is a react app but you can just change the entry point to where your app loads from.
This is quite hard to do of the fly without testing things out, but i hope this gives you enough reference as to what you should change and do to get going with it.
Again i strognly recommend the webpack.js guides and documentation, they are very thorough and once you start getting the hang of it things start working smoothly.

Babel not compiling vendors chuck

I migrated to Webpack 4 and set up everything according to the Docs, however, my vendors.js chunk is not getting compiled like the main.js chunk.
I have placed the vendors into the optimization.splitChunks.cacheGroups object, as the docs suggested, but didnt find a way to make these "cacheGroups" get compiled with babel.
My problem is that one of the libraries has a ES6 class and now IE11 isnt working due to this fact.
My webpack optimization object looks like:
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
},
vendor: {
name: 'vendor',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
enforce: true
}
}
}
}
Is there a way to force webpack to compile vendors with babel as well?
Regards
you should have posted the entire webpack config to give people more context.
Anyways, optimization step has very little to do with the actual transpiling. Your vendor chunk is set to only include stuff from node_modules which is almost never processed (unless you specifically tell babel-loader to include a certain package).
Since I do not know how you configured your babel-loader I would suggest something along these lines:
{
test: /\.js$/,
exclude: (file) => {
return /node_modules/.test(file) && !file.includes("/node_modules/my-es6-module/");
}
}
The idea is to exclude all files containing node_modules unless the file path contains the name of your specific module which you do need to process with babel.
In general, having an ES6 code published to npm is a very bad practice and should be avoided at all costs.
If this is not enough, please do update your question with your webpack config to give us more insight into your setup.

Npm package include images in CSS

I have an npm package with this structure:
--src
--styles
-image.png
-style.scss
The style.scss file is referencing the image like this:
.test {
background-image: url(./image.png);
}
The problem is when I consume the package, CSS is looking the image from the root and not relative to my package, how we can solve this issue?
This is how I'm importing the package:
#import "mypackage/src/styles/style";
I have this issue too and I do not find a elegant way to this issue. Finally I copied the referenced files to the build directory to solve this issue. The "copy-webpack-plugn" plugin was used(https://github.com/kevlened/copy-webpack-plugin)
You may refer to the following issue too(
Include assets from webpack bundled npm package)
All you need just install file loader like this.
npm install file-loader --save-dev
and then add this line to module part in your config :
module: {
rules: [{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
}]
}
I have had this issue recently and the information on StackOverflow was outdated (as expected, this is a question that relates to NPM & Web Development and everything moves fast in this space).
Fundamentally, this problem is solved entirely by Webpack 5 as it comes out of the box. Only the webpack.config.js file needs to be updated.
The part of webpack's documentation that relates to this is here: https://webpack.js.org/guides/asset-modules/
What you want to do is Base64 encode your static assets and inline them to your CSS/JavaScript.
Essentially, when you are packing up your source code to distribute it on NPM, and you have some CSS file which refers to static images as such: background-image: url(./image.png) what you need to do is inline your assets to your style file, and then process your style file with the style-loader and css-loader packages.
In short, making my webpack.config.js contain the lines below solved my issue and allowed me to export one single index.js file with my package, which I imported into my other projects.
What really matters here is the type: asset/inline line, when we are testing for images.
webpack.config.js
...
...
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.(png|jpg|gif)$/i,
type: "asset/inline",
},
],
},
...
...

Webpack 2: How do I generate a bundle.js from Bootstrap premade template?

I want to generate a bundle.js from this pre-esxisting bootstrap template (it uses less) https://github.com/BlackrockDigital/startbootstrap-sb-admin-2
I tried to generate it but I failed since the styles are never generated and the bundle.js is empty as you can see in the "dist" folder(This was expected since the index.js which is the entry point is empty as well. https://github.com/juanlet/webpack . What should I do in order for webpack2 to include all the js,css and less files that came with the template and put it in a bundle.js?. Should I include every file on the index.js entry file?. I'm running out of ideas. Any article, documentation or instruction will be very welcomed. Thank you very much.
If you want to build this out with webpack, your first step is actually using whatever your entry point is to import or require other libs/files.
So, for example, if your entry point in your wepback.config.js is
entry: {
bundle: './src/js/api/index.js',
vendor: VENDOR_LIBS
},
Then that file needs to contain imports that you wish to include in that file. And then those files include other files and so on, until you have all your files bundled up through the root of your tree (index). In a very simple way, this is what webapack does: it imports/requires your files, bundles them, and loads them depending on your configuration.
In order to load/compile your LESS, you will either have to include it as an import in your JS files, or you could also use extract-text-webpack-plugin to generate a separate CSS bundle.
This is the best overview I can give to this question since I don't know the exact way your want to take your code and bundle it. Feel free to ask questions if you have them, and I will edit my answer to try and help answer them.
EDIT: This is an example of an older config I have extracting SASS into it's own file. It's using v1, but it more or less works the same for webpack 2. I just don't have an example with me right now: (Here is the documentation for using extract in v2. A little different, but not too much).
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'babel-polyfill',
'./app/index',
],
resolve: {
extensions: ['', '.js']
},
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js',
publicPath: '/public/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new ExtractTextPlugin('public/app.css'),
new DashboardPlugin(dashboard.setData)
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, '..', 'app')
},
// JSON
{
test: /\.json$/,
loaders: ['json-loader']
},
// Img
{
test : /\.(png|jpg|svg|eot|ttf|woff|raw)$/,
loader: 'url-loader?limit=4096'
},
// Sass
{
test: /\.scss$/,
loaders: [ 'style', 'css?sourceMap', 'postcss', 'sass?sourceMap' ]
}]
},
postcss: [autoprefixer({ browsers: ['last 2 versions'] })],
}
MAJOR EDIT:
An example repo exists here: https://github.com/thesublimeobject/webpack2example
Running webpack will bundle up your files, imported from an index.js file I created. This bundles all the external libraries which I installed via npm and removed them from the index.html file. I did not test any of the code that was generated since that's way beyond an answer to this question. Your LESS will also be bundled into the dist folder as a separate file you will need to provide a link to in the HTML (that's one thing I forgot to do is add links to the /dist, but I'm sure you can do that.

Categories