Resolving javascript files using webpack - javascript

My webpack.config.js contains something like:
...
module.exports = {
entry: './app.js',
output: { path: __dirname + "/dist/", filename: 'bundle.js' },
resolve: {
root: path.resolve('./js')
}
....
}
The documentation suggests resolve can have a root value. But I get the error below.
$ node ./node_modules/webpack/bin/webpack.js
Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
- configuration.resolve has an unknown property 'root'. These properties are valid:
object { alias?, aliasFields?, cachePredicate?, descriptionFiles?, enforceExtension?, enforceModuleExtension?, extensions?, fileSystem?, mainFields?, mainFiles?, moduleExtensions?, modules?, plugins?, resolver?, symlinks?, unsafeCache?, useSyncFileSystemCalls? }
I get the same with modulesDirectories. Not sure which, or if either, I should be using. Any idea how I can pull my JS files in?

You've looked at the documentation for webpack 1. Webpack 2 removed resolve.root and unified it to resolve.modules, as shown in the Migration Guide of the official webpack 2 docs.
The correct way of doing it with webpack 2 is:
resolve: {
modules: [path.resolve('./js'), 'node_modules']
}
But you might have misunderstood what the option does. It does not include all the files in those paths. Webpack starts from your entry point and processes just the files that are being imported (see also Core Concepts). So if you want webpack to include your JavaScript files, you need to import them at some point.
Instead this option tells webpack where to look for the module when you import it (not with a relative path). By default only node_modules is used for resolving Module paths, just like Node.js does it.
For example with this directory structure:
js
├─ components
│  └─ main.js
└─ utils
└─ helper.js
You can import the helper.js file from anywhere in your project with:
import helper from 'utils/helper';
Whereas if you didn't add js/ to the resolve.modules you would need to import it with a relative path. So for instance in js/components/main.js the import would look like this:
import helper from '../utils/helper`;
Obviously the relative path is different depending on which directory you're in.

Related

How does webpack pick a relative path inside node_modules ? does it reference package.json at all?

When i do npm install react-slick, i get the following in my node_modules folder:
Now in my react application in a src/index.js file, when i do the following:
import Slider from "react-slick";
How does webpack know where to pick slider from ? will it at all look for some clue or definition inside node_modules/react-slick/package.json at all ?
Edit :- so here is the package.json file for webpack, when i import Slider from 'react-slick' , does it resolve to dist or lib ? and which file does it pick then and why ?
Well, the simple walkthrough of it will be as below:
Simple Walkthrough
If you carefully look at the node_modules/react-slick/package.json there is a property named main. Something like this:
{
"name": "react-slick",
"main": "index.js"
}
It will tell the Webpack which file is the entry file of the whole package (It's usually referred to index.js). All the necessary exports for the package lies in this file, so Webpack will only look for those exports and will import what you looking for. In this particular case, there should be a default export for the Slider that you using right now. So the index.js is probably something like this:
// index.js
var slider = require('./lib/slider'); // Usually all the main modules are lies under lib folder.
// other imports ...
module.exports = slider;
Difference between lib and dist
Usually, the dist folder is for shipping a UMD that a user can use if they aren't using package management. The lib folder is what package.json, main property points to, and users that install your package using npm will consume that directly. The only use of the lib as opposed to src is to transform your source using babel and Webpack to be more generally compatible since most build processes don't run babel transforms on packages in node_modules.
Webpack uses aliases to target node_modules using a shorthand.
Example #1:
import 'xyz'
/abc/node_modules/xyz/index.js
Example #2:
import 'xyz/file.js'
/abc/node_modules/xyz/file.js
Once it targets the correct folder in node_modules, it follows the rules written in the package itself (manifest, package.json)
You can also define your own aliases as such:
webpack.config.js
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
xyz$: path.resolve(__dirname, 'path/to/file.js')
}
}
};
And then can be used as import xyz from $xyz

Import node modules from priv/static/js folder in Phoenix 1.4

I installed vuejs with a npm install in my assets/ folder and I created a list_show.js file in priv/static/js/list_show.js . When I do import Vue from "vue" in my list_show.js, it doesn't work and I get this message in the console: "Uncaught SyntaxError: Unexpected identifier".
How can I import modules in my static/js/ folder? (I'm using Phoenix 1.4 and Webpack by default)
You should not create your .js files in the /priv/static/js directory. Instead, use the /assets directory.
Phoenix 1.4 uses Webpack to bundle js files located in /assets into a single app.js file which will be placed into /priv/static/js. As an entry point to your application, you can use /assets/js/app.js where the following lines load Vue:
import Vue from 'vue';
new Vue({
// ...
});
(You can also put this code in a seperate .js file, as long as you import it in app.js)
This solution, however, won't help if you need static js files for different routes. You maybe want to always render priv/static/js/app.js, but specific files just on specific layouts. Achieving multiple output files in priv/static/js can be done by modifying your webpack.config.js slightly and adding more entrypoints:
entry: {
app: ['./js/app.js'].concat(glob.sync('./vendor/**/*.js')),
special: ['./js/special.js']
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, '../priv/static/js')},
}
With this config, two files will be created:
priv/static/js/app.js - Containing all vendor files and app.js
priv/static/js/special.js - Containing just special.js
The special.js file can be included within Phoenix then:
<script type="text/javascript" src="<%= Routes.static_path(#conn, "/js/special.js") %>"></script>

Webpack change import path for a specific package

Let's assume, we do have few js libs, that installed into our bundle.
And, for some reason, I need to use a library from node_modules of a library.
I can do import it via
import thing from 'somelib/node_modules/thing';
And I want to do just:
import thing from 'thing';
But behind the scenes, webpack will know - the path should be 'somelib/node_modules/thing'
How can I change/override a specific import path in my webpack config file, so my node will bring me a package from the destination that I want?
I think you are looking for resolve.alias
https://webpack.js.org/configuration/resolve/#resolve-alias
In your webpack config, specify the resolve.modules
This example from the webpack documentation adds the "src" folder.
module.exports = {
//...
resolve: {
modules: [path.resolve(__dirname, 'src'), 'node_modules']
}
};
Or if you really don't want this affecting your other entry points, you could create separate webpack configs. (They can still import settings from a primary file) that allows you to set resolve.aliases and resolve.modules independently for each entry point.

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.

Applying loaders to files imported via resolve.modules in webpack

I have two javascript projects in separate directories within a parent directory and I want both of them to be able to import files from a common directory. The structure looks a bit like this:
- parentDir
- project1
- package.json
- webpack.config.js
- src
- index.js
- project2
- package.json
- webpack.config.js
- src
- index.js
- common
- components
- CommonComponent.vue
- application
- app.js
I'd like both project1's index.js and project2's index.js to be able to import CommonComponent.vue and app.js.
Currently this works if I do:
import CommonComponent from ../../common/components/CommonComponent.vue
However those import paths starts to get very messy and hard to maintain the deeper into each tree we go, with huge numbers of ../s, so I'm trying to find a way of making the imports neater and easier to manage and I came across resolve options in webpack. So I've tried adding this to my webpack.config.js:
resolve: {
modules: [
path.resolve("../common/"),
path.resolve("./node_modules")
]
},
so then the import would look like:
import CommonComponent from "components/CommonComponent.vue"
import app from "application/app"
Importing the plain js file works, but when trying to import the .vue file, webpack throws an error:
ERROR in C:/parentDir/common/components/CommonComponent.vue
Module not found: Error: Can't resolve 'vue-style-loader' in 'C:/parentDir/common/components'
So how can I apply webpack loaders to files imported via resolve.modules?
Note: importing .vue files from within a single project works fine, so my module.rules config is correct.
It turns out the common package needed its own node_modules. That doesn't seem to be the case when importing a file from there directly via its path, but it is when using either resolve.modules or resolve.alias in webpack.
So the answer was to npm init in common and then to npm install all the dependencies and devDependencies needed there. e.g (of course these will depend on the project):
npm install --save vue
npm install --save-dev babel-core babel-loader css-loader less-loader vue-loader vue-template-compiler webpack
Once that's done, both of these webpack configs seem to have the same result as far as I can tell:
resolve: {
modules: [
path.resolve("../../common"),
path.resolve("./node_modules")
]
},
and
resolve: {
alias: {
components: path.resolve("../../common/components")
}
}
Both allow a file in project1 or project2 to do an import like:
import CommonComponent from "components/CommonComponent.vue"

Categories