Can't load a module with custom loader in vue-cli project - javascript

I have a project where Webpack 4.43.0 is set up with vue-cli. I'm trying to use
image-size-loader to get image size at build time.
For that, in one of my .vue files I'm trying to load the module using the custom loader I have installed in the project:
const background = require("image-size!../../../../assets/images/candy.jpg");
When my project builds, it outputs the following error:
ERROR Failed to compile with 1 errors8:47:03 AM
This dependency was not found:
* image-size!../../../../assets/images/candy.jpg in ./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options!./src/vue/guides/tags/hero/TagGroupInvite.vue?vue&type=script&lang=js&
To install it, you can run: npm install --save image-size!../../../../assets/images/candy.jpg
The file is present and js/ts/css files resolve fine. What can be wrong with my setup?

I think you have to specify image-size as a loader too.
Append this loader to webpack.base.conf.js
...
loaders: [
...
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'image-size'
}
...
]
...

Related

After upgrading Angular, webpack module source-map-loader is throwing "this.getOptions is not a function"

I am currently building my angular project via webpack with source-map-loader to extract source maps, like so:
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
enforce: "pre",
use: ["source-map-loader"],
},
],
},
};
This works fine with my Angular 11 build.
Once I upgrade my angular packages to Angular 12, I begin to get the following error:
Module build failed (from ./node_modules/source-map-loader/dist/cjs.js):
TypeError: this.getOptions is not a function
at Object.loader (./node_modules/source-map-loader/dist/index.js:21:24)
Removing this section from my webpack module allows the build to succeed but I am no longer extracting the source maps, causing my bundle to increase in size.
I have tried upgrading source-map-loader to latest version and did not change the error.
I have dug into the node_module and it is complaining about this section of code:
async function loader(input, inputMap) {
const options = this.getOptions(_options.default);
I have seen may other questions on here in regards to sass-loader and other style loaders for Vue but this is for Angular and is mad about extracting source maps.
There are some breaking changes when going to Angular 12 but upgrading to webpack 5.0.0 did not seem to make a difference
What are some other things I can do to debug this?
By looking at the source code v1.1.3 we do see
import { getOptions } from "loader-utils";
But after v2.0 or even v3.0, this import was deleted.
It came from the library loader-utils
Since v2.0, package.json doesn't import it anymore.
Looks like it has been deprecated, getOptions should be use from Webpack type instead of loader-utils.
Maybe your error come from a conflict with an old dependencie from your node_modules, you should remove the old one from your directory and try again
rm -rf node_modules/#types/loader-utils
rm -rf node_modules/loader-utils

How to install a npm package from local folder and develop on both the folder simultaneously?

I am working on a React project and using Webpack to compile the code. This project contains a lot of common components which is installed in other projects across the organisation using npm install private git repository.
Package.json of other project looks like this:
"#mypackage/my-package-name": "git+ssh://git#github.com:git-handle/git-repo.git",
And in Webpack config I am compiling it by excluding it from node modules and it works fine.
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules(?!\/#mypackage))/,
use: [
{
loader: 'babel-loader',
query: {
presets: ['#babel/react'],
},
},
],
},
],
},
Now when I want to update the code of common component from the global package I have to reinstall the whole package to check the changes.
One workaround for that is to edit the node_modules but then I have to redo those changes to my global package and again do the reinstalling process at the end ( also it doesn't keep the git history to track what changes needs to be done ).
I have came across npm install from local and npm link local folder answer but facing the same issue which is not resolved
Updated package.json
"#mypackage/my-package-name": "file:../my-package-name"
I got the following errors
Module not found: Can't resolve '#mypackage/my-package-name/Navbar' in 'path/to/folder/'
SassError: File to import not found or unreadable: bootstrap/variables
Module not found: Error: Can't resolve 'js-cookie'
These errors are may due to an incomplete compilation of code from local folder.
My folder structure is something like this
= (my-package)
- package.json
- ...
= src
- index.js
= (other-project)
- package.json
- ...
= src
- index.js
I am looking for a solution by which I can point the package to a local folder( mypackage global folder ) and synchronize the changes in both the projects.

How to use node_modules on a "traditional website"?

I have used node to manage dependencies on React apps and the like, in those you use package.json to keep track of libs and use them in your scripts using ES6 import module syntax.
But now I'm working on a legacy code base that uses a bunch of jQuery plugins (downloaded manually and placed in a "libs" folder) and links them directly in the markup using script tags.
I want to use npm to manage these dependencies. Is my only option:
run npm init
install all plugins through npm and have them in package.json
link to the scripts in the node_modules folder directly from the markup:
<script src="./node_modules/lodash/lodash.js"></script>
or is there a better way?
Check out this tutorial for going from using script tags to bundling with Webpack. You will want to do the following: (Do steps 1 and 2 as you mentioned in your question then your step 3 will change to the following 3 steps)
Download webpack with npm: npm install webpack --save-dev
Create a webpack.config.js file specifying your entry file and output file. Your entry file will contain any custom JS components your app is using. You will also need to specify to include your node_modules within your generated Javascript bundle. Your output file will be the resulting Javascript bundle that Webpack will create for you and it will contain all the necessary Javascript your app needs to run. A simple example webpack.config.js would be the following:
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
resolve: {
alias: {
'node_modules': path.join(__dirname, 'node_modules'),
}
}
};
Lastly, add a <script> tag within your main HTML page pointing to your newly generated Javascript bundle:
<script src="dist/my-first-webpack.bundle.js"></script>
Now your web application should work the same as before your refactoring journey.
Cheers
I recommend Parcel js.
Then you only need:
Run npm init
Install dependency, for example npm install jquery
Import with ES6 syntax: import $ from "jquery";
And run with parcel

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.

Webpack Loader not Working on Jenkins CI Build

I'm trying to integrate Weback into my current project and am having problems with a custom loader I built to create a concat banner and footer around each module's file contents, and to inject the __filenamevalue. Everything works great doing local builds with grunt
https://github.com/optimizely/marketing-website/tree/dfoxpowell/jordan-webpack-try/grunt/webpack
grunt server
//or
grunt build --env=production //production build for uglify/dedupe
Our staging build on Jenkins successfully runs the loader using grunt staging-deploy --branch=$branch --env=production
Our production build uses a Docker container and a deploy.sh script which runs grunt build --env=production. This build for some reason fails to run the loader although grunt build --env=production locally will successfully run the loader and build the assets.
I resorted to hardcoding the loader into the repo and requiring it by path in the make-webpack.config.js in order to debug if this was some sort of installation issue on Jenkins but this didn't help.
https://github.com/optimizely/marketing-website/blob/dfoxpowell/jordan-webpack-try/loaders/inject-filename-loader.js
I know this is most likely a difficult question to answer without access to our Jenkins deploy environment but any info you could offer for help debugging would be extremely helpful.
I created an issue in the Weback repo here that basically states the same info as above.
Update
I took this suggestion Injecting variables into webpack and added
resolveLoader: {
modulesDirectories: ['loaders', 'node_modules'],
extensions: ['', '.loader.js', '.js']
}
to my webpack.config and put my loaders directory in the root of my project. Unfortunately, the result is still the same and the loader doesn't run in prod on Jenkins.
Here is the solution I found to this issue:
Our CI build was installing our project from Git as a node_module through NPM rather than using git clone. Therefore, there was a node_modules directory at the root of the CI build, and the project was being built inside of this directory.
node_modules/<project npm package name>/{node_modules,grunt/webpack/...configs}
Therefore, it seems the loader was being looked for in the wrong node_modules directory, but it is strange that other loaders that I was using such as babel and handlebars were being sourced correctly.
When I used the loader path directly in the loader config
var injectFilenamePath = path.join(process.cwd(), 'grunt/webpack/inject-filename-loader');
console.log('LOADER PATH => ', injectFilenamePath);
var loaders = [
{
test: /\.js$/,
exclude: [
/node_modules/,
/bower_components/,
/libraries/
],
loader: injectFilenamePath + '?' + opts.injectFileNameParams
},
{ test: /\.hbs$/, loader: 'handlebars-loader' },
{test: /\.js?$/, exclude: ['bower_components', 'node_modules'], loader: 'babel-loader'}
];
the console output was
LOADER PATH => /opt/tmp/node_modules/marketing-website/grunt/webpack/inject-filename-loader
and after cloning our repo rather than npm i the path was
LOADER PATH => /opt/tmp/marketing-website/grunt/webpack/inject-filename-loader
Not sure if this somehow expected behavior but hopefully it saves others from similar issues if they arise.

Categories