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.
Related
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.
I am working with this Angular starter pack, works awesome, would recommend.
https://github.com/preboot/angular-webpack
However in the project I would like to have one global app.scss which contains more _partial.scss files, like most sass projects, then have the components encapsulated scss files inside they're own directory, which also use the globals scss file.
However when I try to import a partial scss file into app.scss I get this error in my browsers console.
./~/css-loader!./~/postcss-loader!./~/sass-loader/lib/loader.js!./src/style/app.scss
Module build failed:
#import 'settings/_color';
^
File to import not found or unreadable: settings/_color.
The files are definitely in the right directory, I just can work out why webpack cannot compile them.
I'm pretty sure it is on this line: 121
{
test: /\.(scss|sass)$/,
exclude: root('src', 'app'),
loader: isTest ? 'null-loader' : ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'postcss-loader', 'sass-loader']})
}
can anyone help I can get the app.scss to compile successfully with the partial files?
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",
},
],
},
...
...
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.
I setup React+Webpack project. It take 60s to build an initial bundle, and 1s to append incremental change but I even don't have my application code yet! Seems that bundle of node_modules is very expensive. I tried splitting using common chunks, but it didn't give performance improvement.
How can I make Webpack bundle node_modules only once, and even don't watch for changes in this dir?
If that's a problem, you don't need to bundle external dependencies in your project. You can add them as external dependencies. For that, of course, you should add the scripts to your page.
Let's say you add the react and react-dom scripts to your page, in the webpack config file you could add this:
{
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
}
What this tells webpack is every time you require('react') or webpack will return a global variable called React. Same thing if you require('react-dom')
And for every loader, you should either include the files you want or exclude the files you don't need.
Here's an example excluding node_modules:
{
module: {
loaders: [
{
test: /\.jsx?/,
exclude: /node_modules/,
loader: 'babel'
}
]
}
}
Or even more performant, you can just include the files you need:
{
module: {
loaders: [
{
test: /\.jsx?/,
include: './src',
loader: 'babel'
}
]
}
}