Webpack2 rules 'test'-expression doesn't load '?'-modules after migration - less

I want to be able to use two different loaders for '*.less' files.
Default one for all, but other for '*.less?module' files.
In webpack 1.x it was possible through:
module: {
rules: [
{
test: /\.less$|\.css$/,
use: ...
},
{
test: /\.less\?module$/,
use: ...
},
How to do it in webpack 2 or 3?

Related

Appropriate Loader Setup for the Images in vue js

I'm struggling with the Setting up Loaders for my VueJS project (vue3), to be more specific i have a following structure of the folders
My Images is located at path called assets and I would like url-loader to know, that he need to grab images from THIS path.
my loaders configuration at vue.config.js looks following
configureWebpack: {
module: {
rules: [
{ test: /\.(jpg|jpeg|png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader',
options: {limits: 100000, name: "/assets/[name].[ext]"}},
],
}
},
If there is any obvious mistakes PLEASE point out on them.
Cuz i'm not really sure if i did it right

Failed to compile on React Native Web

I am trying to render a calendar from https://github.com/wix/react-native-calendars
I am getting a failed to compile error:
./node_modules/react-native-calendars/src/expandableCalendar/asCalendarConsumer.js
Module parse failed: Unexpected token (11:8)
You may need an appropriate loader to handle this file type.
| render() {
| return (
| <CalendarContext.Consumer>
| {(context) => (
| <WrappedComponent
I think is based on my webpack setup:
// webpack.config.js
module.exports = {
plugins: ["#babel/plugin-syntax-dynamic-import"],
resolve: {
alias: {
'react-native$': 'react-native-web'
},
},
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: ['babel-preset-env', 'babel-preset-stage-0'],
plugins: ["#babel/plugin-syntax-dynamic-import"],
}
},
{
test: /\.js$/,
loader: 'babel-loader',
options: {
presets: ['babel-preset-env', 'babel-preset-stage-0'],
}
},
{
test: /\.ttf$/,
loader: "url-loader", // or directly file-loader
include: path.resolve(__dirname, "node_modules/react-native-vector-icons"),
},
]
}
But I am not really an expert on webpack.
The library seems to work with React Native Web - so what am I doing wrong that is causing me to not have it work with my setup?
Found the solution. Make sure to INCLUDE it in babel-loader. To fix it do the following:
1- Make sure to include the package folder in the babelLoader configuration in webpack.config.js as
include: [path.resolve(appDirectory, 'node_modules/react-native-calendars'), ...]
NOTE: Don't forget to also include all the directories that require babel-loader.
2- (Might need it)- You might need to go to node_modules/react-native-calendars/src/calendar/index.js and to node_modules/react-native-calendars/src/agenda/index.js and REMOVE the propTypes declarations and the ViewPropTypes import from react-native on lines 2, 20, and 32 on both files. Here's how */agenda/index.js is supposed to look like. Until the devs fix this, avoid updating the package or you will lose the changes. (I am including this because it happened to me right after step 1 so just in case)
https://gist.github.com/iosvanyd1/abd18bd35ce3fdcb635100ce5d5b0beb

responsive-loader with nuxt.js

I want to integrate responsive-loader into my Nuxt.js project which runs in SPA mode. (Optional I want to add Vuetify Progressive Image support also).
It will be a static hosting with Netlify.
Versions:
"nuxt": "^2.3.4"
"responsive-loader": "^1.2.0"
"sharp": "^0.21.1"
I found some solutions how to do it (https://stackoverflow.com/a/51982357/8804871) but this is not working for me.
When I run npm run build
I get an error message: "TypeError: Cannot set property 'exclude' of undefined"
My build section looks the following:
build: {
transpile: [/^vuetify/],
plugins: [
new VuetifyLoaderPlugin()
],
extractCSS: true,
/*
** Run ESLint on save
*/
extend(config, { isDev, isClient, isServer }) {
// Default block
if (isDev && isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
if (isServer) {
config.externals = [
nodeExternals({
whitelist: [/^vuetify/]
})
]
}
// Default block end
// here I tell webpack not to include jpgs and pngs
// as base64 as an inline image
config.module.rules.find(
rule => rule.loader === "url-loader"
).exclude = /\.(jpe?g|png)$/;
/*
** Configure responsive-loader
*/
config.module.rules.push({
test: /\.(jpe?g|png)$/i,
loader: "responsive-loader",
options: {
min: 350,
max: 2800,
steps: 7,
placeholder: false,
quality: 60,
adapter: require("responsive-loader/sharp")
}
});
}
}
The error is probably found in this section:
config.module.rules.find(
rule => rule.loader === "url-loader"
).exclude = /\.(jpe?g|png)$/;
Like said I get this error message: "TypeError: Cannot set property 'exclude' of undefined".
I run this project along with vuetify. I also would like to enable the Progressive image support together with responsive loader. Does anybody know how to setup both rules together?
https://github.com/vuetifyjs/vuetify-loader#progressive-images
The easiest way to integrate responsive-loader into a Nuxt.js project is to use this module: https://www.npmjs.com/package/nuxt-responsive-loader
Disclaimer: I created the module
The problem with your config that it relies on rule.loader property but rule can be defined in use or oneOf config sections as well.
Another one problem is that nuxt internal config has several rules with url-loader(for images, videos, fonts ...).
In your case the rule, you tried to find, has use section and url-loader is defined there, that's why your find function found nothing and threw this error:
{
"test": /\.(png|jpe?g|gif|svg|webp)$/,
"use": [{
"loader": "url-loader",
"options": {
"limit": 1000,
"name": "img/[hash:7].[ext]"
}
}]
}
About responsive-loader, you should remove extensions you want to process with responsive-loader from url-loader rule to avoid unexpected behavior and conflicts, here is extend function working example:
extend(config, ctx) {
let imgTest = '/\\.(png|jpe?g|gif|svg|webp)$/';
// find by reg ex string to not rely on rule structure
let urlRule = config.module.rules.find(r => r.test.toString() === imgTest);
// you can use also "oneOf" section and define both loaders there.
// removed images from url-loader test
urlRule.test = /\.(svg|webp)$/;
config.module.rules.push({
test: /\.(png|jpe?g|gif)$/,
loader: "responsive-loader",
options: {
// place generated images to the same place as url-loader
name: "img/[hash:7]-[width].[ext]",
min: 350,
max: 2800,
steps: 7,
placeholder: false,
quality: 60,
adapter: require("responsive-loader/sharp")
}
})
}
Yes, it looks dirty, but I think it's only way for now to change some loader.
What about vuetify - I think both loaders will conflict with each other and probably the solution is to use single loader that will work with your images.
Hope it helps.
Update for Nuxt >= 2.4.0:
They modified the rules array please update the following line:
let imgTest = '/\\.(png|jpe?g|gif|svg|webp)$/i';
Then the code should work normally again.

Two compile cases with Webpack, Vue.js, and Sass

I'm using Webpack (v4), Sass and Vue.js (v2) in my project.
In some cases, I'd like to compile sass code into .css files. (This is for the .scss files that are mentioned in webpack.config.js as "entry" points)
In some other cases I'd like to have the compiled sass code injected into a html tag. (This is for the <style lang="sass"> included in my .vue single file components)
Is it possible to have both at the same time? How should I configure Webpack?
You can use sass-loader to include scss files anywhere and compile them:
https://github.com/webpack-contrib/sass-loader
To include scss in a single-file-component, you don't have to do anything specific, just write your styles into a style tag specifying lang="scss".
Here is a detailed example for both cases:
https://medium.com/hong-kong-tech/use-sass-scss-of-webpack-in-vuejs-8dde3a83611e
You can only leave scss files for webpack to process. You can't get them processed during build time and inject them into your single components, as stated here "In some other cases I'd like to have the compiled sass code injected into a html tag. (This is for the included in my .vue single file components)".
You have to leave to webpack the burden to compile all your scss files into css. Then you choose to either extract them or leave them in the html style tag.
Sorry PlayMa256 & Máté, for being so long before answering your replies.
In the end I found the solution of using two different configurations for my two cases. Webpack allows it through its multi-compiler feature.
So here is what my webpack.config.js now looks like:
module.exports = [ // notice that we are handling an array of configurations here
// In this first config, I manage the first of my use cases:
// Compilation of .scss files into .css files
{
name: "css",
entry: { /* ... */ },
output: { /* ... */ },
/* ... */
module: {
rules: [
{
test: /\.scss$/,
use: [ MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader' ],
}
]
},
plugins: [ /* ... */]
},
// In this other config, I manage the other of my use cases:
// injection of the <style> blocks of my .vue files into the DOM
{
name: "main", // name for first configuration
entry: { /* ... */ },
output: { /* ... */ },
/* ... */
module: {
rules: [
// Vue single file components loader
{
test: /\.vue$/,
loader: 'vue-loader',
},
// Injection of <style> elements into the DOM,
// for both plain `.css` files and `<style>` blocks in `.vue` files
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
// Compilation of sass code,
// (This actually works both for `.css` files and `<style>` blocks in `.vue` files,
// but I don't have any `.css` as entry for this config.)
{
test: /\.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
}
]
},
plugins: [ /* ... */]
}
];

npm - package.json override main field

I use some npm packages in my project. Two of them have the wrong main-field. Is it possible to override them?
I use webpack. I found a solution here.
This works for the main field but I also need a css-file from the same package. I refer it with ~package/css/style.css in my index.scss file. With the solution above it resolves the path with path/to/main.js/css/style.css (with main.js) instead of path/to/css/style.css (without main.js).
I could refer it directly ../node_modules/path/to/css/style.css but I think thats ugly.
So is there an other solution with webpack or npm to override this main field?
-- EDIT --
I use bootstrap-treeview as package. I refer it in index.scss like so
#import '~bootstrap-treeview/src/css/bootstrap-treeview.css';. This works.
When I add 'bootstrap-treeview': path.join(_path, 'node_modules', 'bootstrap-treeview', 'src', 'js', 'bootstrap-treeview.js') as alias in webpack import 'bootstrap-treeview'; works but the css not (as describes above).
-- EDIT 2 --
webpack.conf.js:
resolve: {
extensions: ['', '.js'],
modulesDirectories: ['node_modules'],
alias: {
// bootstrap-treeview alias
'bootstrap-treeview': path.join(_path, 'node_modules', 'bootstrap-treeview', 'src', 'js', 'bootstrap-treeview.js')
}
},
module: {
loaders: [
{
test: /\.css$/,
loaders: [
'style-loader',
'css-loader?sourceMap',
'postcss-loader'
]
},
{
test: /\.(scss|sass)$/,
loader: 'style-loader!css-loader?sourceMap!postcss-loader!sass-loader?outputStyle=expanded&sourceMap=true&sourceMapContents=true
}
]
}
index.scss see above.
Error with bootstrap-treeview alias:
Module not found: Error: Cannot resolve 'file' or 'directory' /home/ekf/develop/generator-angular-webpack/node_modules/bootstrap-treeview/src/js/bootstrap-treeview.js/src/css/bootstrap-treeview.css in ...
Error without alias:
Module not found: Error: Cannot resolve module 'bootstrap-treeview' in ...
just in case
webpack scss loader config
module: {
loaders: [
{
test: /\.css$/,
exclude: /node_modules/,
loader: "style-loader!css-loader"
},
{
test: /\.scss$/,
exclude: /node_modules/,
loader: "style-loader!css-loader!sass-loader"
}
]
}
The problem is that your alias points directly to the JS file, instead of pointing to the common ancestor of both the JS and the CSS. It's nice and convenient to be able to import Treeview from "bootstrap-treeview" but it leads to the problem you're describing.
Instead, you could specify a higher level alias:
resolve: {
alias: {
// bootstrap-treeview alias
'bootstrap-treeview': path.join(_path, 'node_modules', 'bootstrap-treeview', 'src')
}
},
and get the JS as import Treeview from "boostrap-treeview/js/bootstrap-treeview.js". This allows you to get the CSS as require("bootstrap-treeview/css/bootstrap-treeview.css").
You might be able to get clever about it and tell Webpack to look for CSS files in ~/css/ and JS files in ~/js/ but that would be adding more magic for (IMHO) little gain.