Question
Is it possible to specify modules to be hidden (ignored) in printed output by webpack --display-modules --display-reasons?
Setup
structure
.
├── build
│ └── index.js
├── package.json
├── src
│ ├── hello
│ │ └── index.js
│ ├── index.js
│ ├── util
│ │ └── index.js
│ └── world
│ └── index.js
└── webpack.config.js
package.json
{
"private": true,
"scripts": {
"start": "webpack --display-modules --display-reasons"
},
"devDependencies": {
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.9.0",
"webpack": "^1.13.1"
},
"dependencies": {
"core-js": "^2.4.0",
"lodash": "^4.13.1"
}
}
src/index.js
import hello from './hello'
import world from './world'
console.log(`${hello()} ${world()}`);
src/hello/index.js
import util from '../util';
const _ = require('lodash');
const hello = () => _.capitalize(`hello${util()}`);
export default hello
src/world/index.js
import util from '../util';
const _ = require('lodash');
const world = () => _.capitalize(`world${util()}`);
export default world
src/util/index.js
export default () => '!'
webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
filename: './build/index.js'
},
module: {
loaders: [
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: 'es2015'
}
}
]
}
};
Motivation
By running webpack I get this stunning program in build/index.js which prints:
Hello! World!
More interesting part is in output printed by webpack --display-modules --display-reasons:
This output is very powerful:
immediately see project structure
recognise which modules are required by other modules
how many times those modules are reused
where those modules are required in other modules
used module format
is it my module or from node_modules
looks super cool
Mentioned above pros connivence me to use this output in daily work.
But can be problem with it.
Problem
When I use big external package with a lot of modules it can blur my output from previous picture. You can see it when add for example core-js to my files:
src/index.js (modified)
require('core-js'); // new problematic package
import hello from './hello'
import world from './world'
console.log(`${hello()} ${world()}`);
Now my output printed by webpack --display-modules --display-reasons looks like this:
This output is quite long (it's hard to scroll to top). core-js blooded my previously output and I lost mentioned previous pros of analyze it.
Tips
problematic output isn't always at the end
problem isn't related only with core-js (it's only example)
switching to pre-build sources isn't solution
require of problematic package must occurs in source .js files not in webpack.config.js
To exclude more than one folder add the following to webpack.config.js
stats: {
exclude: [
"node_modules",
"bower_components",
"jam",
"components",
"my-custom-folder"
]
}
without using --display-exclude
In webpack there is undocumented option --display-exclude which, as described in source code, exclude modules in the output.
This is exactly what you need, so, pass this parameter to webpack cli:
webpack --display-modules --display-reasons --display-exclude="core-js"
Related
I have a component sharedlib outside the babel root directory of project1. I used to use webpack to package this project without problems, but when I configured babel, I got the following error:
Asset Size Chunks Chunk Names
lib1.out.js 63.1 KiB main [emitted] main
lib1.out.js.map 43.2 KiB main [emitted] [dev] main
Entrypoint main = lib1.out.js lib1.out.js.map
[../sharedlib/index.js] 43 bytes {main} [built]
[../sharedlib/util.js] 554 bytes {main} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
[./src/lib1.js] 435 bytes {main} [built]
+ 56 hidden modules
ERROR in ../sharedlib/util.js
Module not found: Error: Can't resolve '#babel/runtime-corejs3/core-js-stable/promise' in 'D:\test_babel\sharedlib'
# ../sharedlib/util.js 3:0-69 13:13-21
# ../sharedlib/index.js
# ./src/lib1.js
ERROR in ../sharedlib/util.js
Module not found: Error: Can't resolve '#babel/runtime-corejs3/helpers/classCallCheck' in 'D:\test_babel\sharedlib'
# ../sharedlib/util.js 1:0-76 7:4-19
# ../sharedlib/index.js
# ./src/lib1.js
ERROR in ../sharedlib/util.js
Module not found: Error: Can't resolve '#babel/runtime-corejs3/helpers/createClass' in 'D:\test_babel\sharedlib'
# ../sharedlib/util.js 2:0-70 10:2-14
# ../sharedlib/index.js
# ./src/lib1.js
The demo project to reproduce the problem is on github https://github.com/xybei/test_babel
My project directory is like this:
ROOT
├─project1
│ │ babel.config.js
│ │ demo.html
│ │ demo.js
│ │ package-lock.json
│ │ package.json
│ │ webpack.config.js
│ │
│ ├─node_modules
│ └─src
│ lib1.js
│
└─sharedlib
index.js
util.js
package.json
Here's the project1/package.json, I have configured sharedlib as a local module "sharedlib": "file:../sharedlib"
{
"name": "lib1.js",
"version": "1.0.0",
"description": "test project1",
"main": "lib1.js",
"dependencies": {
"#babel/runtime-corejs3": "^7.18.3",
"sharedlib": "file:../sharedlib"
},
"devDependencies": {
"#babel/core": "^7.18.2",
"#babel/plugin-transform-runtime": "^7.18.2",
"#babel/preset-env": "^7.18.2",
"babel-loader": "^8.2.5",
"babel-loader-exclude-node-modules-except": "^1.2.1",
"webpack": "^4.39.3",
"webpack-cli": "^3.3.8"
},
"scripts": {
"clean": "rimraf dist",
"prebuild": "npm run clean",
"prerelease": "npm run clean",
"build": "webpack --mode development",
"release": "webpack --mode production"
}
}
webpack.config.js
const path = require('path');
module.exports = {
devtool: 'source-map',
entry: './src/lib1.js',
output: {
path: __dirname,
filename: `lib1.out.js`,
library: 'Lib1',
libraryTarget: 'umd',
libraryExport: 'default',
globalObject: 'this',
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
// include: [
// path.resolve(__dirname, 'src'),
// path.resolve(__dirname, 'node_modules/sharedlib')
// ],
use: {
loader: "babel-loader"
}
}
]
}
};
If I comment out exclude and let go of include, the compilation will no longer report an error, but the util.js in packaged file has not been transpiled, and it is still ES6 code. This is contrary to my expectation. Why is the node_modules/sharedlib directory included, but the files in it are not transpiled?
babel.config.js
module.exports = {
presets: [
["#babel/preset-env",
{
targets: {
ie: 10
},
debug: true
}]
],
plugins: [
[
"#babel/plugin-transform-runtime", {
corejs: 3
}
]
]
};
sharedlib comes from a third party, I don't want to modify and install #babel/runtime-corejs3 under its directory, can I modify the configuration of my project1 to transpile the sharedlib code? thanks for help!
Add #babel/runtime-corejs3 to your sharedlib package.json dependency.
{
"name": "sharedlib",
"version": "1.0.0",
"description": "test sharedlib",
"main": "index.js",
"module": "index.js",
"dependencies": {
"#babel/runtime-corejs3": "^7.18.3"
}
}
When you use Babel's #babel/plugin-transform-runtime, you need to add appropriate runtime dependency to the project. For corejs: 3 option, you would need #babel/runtime-corejs3. Look at the required dependencies you need to additionally install in order for this to run.
Further, you should use package import instead of relative import:
// Instead of this:
import { Util } from '../../sharedlib';
// Use this:
import { Util } from 'sharedlib';
Also, you would need to install this inside sharedlib folder's node_modules since that's where the util.js file is present.
Without modifying sharedlib
To make this work without modifying sharedlib package.json file, make Webpack aware of #babel/runtime-corejs3 using resolve.alias. Modify and add following to webpack.config.js:
module.exports = {
// Other Webpack configuration
resolve: {
alias: {
'#babel/runtime-corejs3': path.resolve(__dirname, './node_modules/#babel/runtime-corejs3')
}
}
};
However, this is not a clean way of doing it. The right approach would be to use a mono-repo setup like npm workspaces or similar and have your node_modules folders all the way up in the ROOT of the repository. That way, Webpack will not have problem resolving required modules from anywhere in the project structure.
I have .js files inside of a dot directory that are not being linted by gulp-eslint.
Example: .foo/file1.js
I've confirmed that the glob is picking up the files inside of the dot directory.
gulp-eslint is passing successfully for the files inside of a parent dot directory even when an intentional error is introduced inside these files.
I've confirmed that directories without a . in the name of the directory (e.g. src/file.js, etc.) are failing linting, when the same intentional error is introduced.
My project structure is something like this:
project/
│
├── .foo/
│ ├──file1.js
│ └──file2.js
│
├── src/
│ ├──file1.js
│ └──file2.js
│
├── gulpfile.js
└── .eslintrc
Contents of gulpfile.js
const gulp = require('gulp');
const eslint = require('gulp-eslint');
gulp.task('lint', () => {
return gulp.src([ './src/**/*.js', './.foo/**/*.js' ])
.pipe(eslint({
configFile: './.eslintrc'
}))
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
Contents of .eslintrc
// Reducing down to a single, simple rule
{
"env": {
"es6": true
},
"rules": {
"quotes": [
"error",
"single"
]
}
}
Is there something incorrect in my config that is preventing the .js files inside of the dot directory .foo from being linted?
Thanks!
It looks to be a known "quirk" of eslint (as of 6.8.0).
The workaround (until a PR is merged to fix this) is to use an .eslintignore file to unignore dot directories explicitly:
#.eslintignore
!.foo
I have this structure of an app (node_modules dir excluded from this list):
├── actions.js
├── bundle.js
├── components
│ ├── App.js
│ ├── Footer.js
│ ├── Link.js
│ ├── Todo.js
│ └── TodoList.js
├── Containers
│ ├── AddTodo.js
│ ├── FilterLink.js
│ └── VisibleTodoList.js
├── index.html
├── index.js
├── main.js
├── package.json
├── package-lock.json
├── reducers.js
└── webpack.config.js
My webpack config looks like this:
module.exports = {
entry: "./main.js",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}
]
}
};
npm config:
{
"name": "webpack-redux",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "nothing"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel": "^6.23.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-es2015": "^6.24.1",
"webpack": "^3.5.5"
},
"dependencies": {
"react": "^15.6.1",
"babel-preset-react": "^6.24.1",
"react-dom": "^15.6.1",
"react-redux": "^5.0.6",
"redux": "^3.7.2"
}
}
When I run webpack command, I get this error:
ERROR in ./components/App.js
Module not found: Error: Can't resolve '../containers/AddTodo' in '/home/oerp/js-programs/redux-test/components'
# ./components/App.js 11:15-47
# ./index.js
# ./main.js
ERROR in ./components/Footer.js
Module not found: Error: Can't resolve '../containers/FilterLink' in '/home/oerp/js-programs/redux-test/components'
# ./components/Footer.js 11:18-53
# ./components/App.js
# ./index.js
# ./main.js
ERROR in ./components/App.js
Module not found: Error: Can't resolve '../containers/VisibleTodoList' in '/home/oerp/js-programs/redux-test/components'
# ./components/App.js 15:23-63
# ./index.js
# ./main.js
My components/App.js content is this:
import Footer from './Footer'
import AddTodo from '../containers/AddTodo'
import VisibleTodoList from '../containers/VisibleTodoList'
const App = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
)
export default App
And for example containers/AddTodo.js:
import { connect } from 'react-redux'
import { addTodo } from '../actions'
let AddTodo = ({ dispatch }) => {
let input
return (
<div>
<form
onSubmit={e => {
e.preventDefault()
if (!input.value.trim()) {
return
}
dispatch(addTodo(input.value))
input.value = ''
}}
>
<input
ref={node => {
input = node
}}
/>
<button type="submit">
Add Todo
</button>
</form>
</div>
)
}
AddTodo = connect()(AddTodo)
export default AddTodo
It seems it does not understand relative path with double dots, like ../something?
Do I need to configure webpack somehow for it to understand such paths?
Your file structure says that folder name is Container with a capital C. But you are trying to import it by container with a lowercase c. You will need to change the import or the folder name because the paths are case sensitive.
I met this problem with typescript but forgot to add ts and tsx suffix to resolve entry.
module.exports = {
...
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
};
This does the job for me
while importing libraries use the exact path to a file, including the directory relative to the current file, for example:
import Footer from './Footer/index.jsx'
import AddTodo from '../containers/AddTodo/index.jsx'
import VisibleTodoList from '../containers/VisibleTodoList/index.jsx'
Hope this may help
You have to instruct the webpack to resolve the source code by using below code in webpack.config.js
module.exports={
...
resolve:{
extensions:['.js','.jsx'];
}
}
Update : There is a new build tool "Vite" that aims to provide a faster and leaner development experience for modern web projects. Its is a plug and play tool, requires very less configuration.
Just ran into this... I have a common library shared among multiple transpiled products. I was using symlinks with brunch to handle sharing things between the projects. When moving to webpack, this stopped working.
What did get things working was using webpack configuration to turn off symlink resolving.
i.e. adding this in webpack.config.js:
module.exports = {
//...
resolve: {
symlinks: false
}
};
as documented here:
https://webpack.js.org/configuration/resolve/#resolvesymlinks
If you use multiple node_modules (yarn workspace etc), tell webpack where they are:
externals: [nodeExternals({
modulesDir: path.resolve(__dirname, '../node_modules'),
}), nodeExternals()],
Had the same issue with module not found. Turns out I had a component
import Picture from './Picture/Picture'; at the very bottom of all the imports. When I moved it below import React, { Component } from 'react';, it worked.
Just add it to your config. Source: https://www.jumoel.com/2017/zero-to-webpack.html
externals: [ nodeExternals() ]
Look the path for example this import is not correct
import Navbar from '#/components/Navbar.vue'
should look like this
** import Navbar from './components/Navbar.vue'**
I had a different problem. some of my includes were set to 'app/src/xxx/yyy' instead of '../xxx/yyy'
changing templateUrl: '' to template: '' fixed it
What I'm trying to do
I am wrote a dummy module my-component which essentially exports a single class Something. I placed it in app/modules/. Now I am tying to access it using the import Syntax from app/app.js:
import { Something } from 'my-component';
Expectation: With my current Webpack configuration (below) I would expect this to work.
Actual: This throws the error:
ERROR in [default] /<project_dir>/app/app.ts:1:26
Cannot find module 'my-component/Something'.
What I tried to fix it
I know the module in itself is defined correctly, because
I can import it using a relative path: import { Something } from './my-component'
I can import it as-is, if I move the module to node_modules/my-component.
The only combination that fails is importing it without a relative path from my modules/ directory. So I think the issue might be my Webpack configuration.
Setup Details
As you can see below, I have two directories listed as resolve.root:
project_dir/app
project_dir/node_modules
It seems to manage to resolve from node_modules, just not from app.
Project layout
Webpack
project_dir/
├── app/ context, resolve.root
│ ├── app.ts
│ └── my-component/
│ ├── index.ts
│ └── Something.ts
├── webpack.config.js
├── node_modules/ resolve.root
│ ├── ...
│ ├── ...
│ └── ...
└── dist/
└── ...
app/app.ts
import { Something } from 'my-component/Something';
app/my-component/index.ts
export { Something } from './Something'
app/my-component/Something.ts
class Something {
}
export { Something };
webpack.config.js
var path = require('path'),
ROOT = path.resolve(__dirname, '.');
module.exports = {
context: path.resolve(ROOT, 'app'),
entry: 'app.ts',
output: {
path: path.resolve(ROOT, 'dist'),
filename: '[name]-[hash].js'
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'awesome-typescript' }
]
},
resolve: {
root: [
path.resolve(__dirname, 'app'),
path.resolve(__dirname, 'node_modules')
],
extensions: [
'', '.ts', '.js'
]
}
};
EDIT
Fixed the project layout.
Cannot find module
If you experience this issue with dynamic module loading using ESNEXT,
you have to add "moduleResolution": "node" to your tsconfig.json.
I found an easier solution than the previously accepted one:
In your typescript configuration, set the baseUrl in the compilerOptions:
tsconfig.json:
{
"compilerOptions": {
"baseUrl": "./app",
...
},
...
}
Explanation:
Webpack and Typescript use node module resolution by default, which is fine.
When setting up custom module folders though, you need to configure them in both the Webpack and the Typescript config.
Changes to the Webpack module resolution config are not propagated to the Typescript compiler.
Ok. I created a replica of your project structure. It seems that the case is that the import statement does not behave the same as the require, AND, webpack resolve.root config works as expected with it.
For the modules, change your import statements to require like this:
app.ts
// Define require function for TypeScript to know that it
// will exist at runtime
declare function require(name:string);
// Require your module
var Something = require('my-component/Something');
// var myComponent = require('my-component');
my-component/Something.ts
// Export something (used a function to test)
export function Something() {
console.log("Hello");
}
my-component/index.ts
// Definition of require function as mentioned before
declare function require(name:string);
// Passing other modules
var exportedModules = {
Something: require("my-component/Something")
};
export default exportedModules;
Like this, it will work without problems and resolve with the module names as you defined in Webpack. Unfortunately, I couldn't achieve it with the import.
I pushed the solution to a repository. Check it out if you need!
I'm trying to write a system of modular components that can be dynamically loaded at runtime with webpack. For example, when the user switches tabs, the code to display the content of the new tab should only load when the user clicks on that tab.
Here is some of the code that accomplishes this (quite nicely, I might add):
onrender(){
this.observe("route", (route) => {
if(route.length>0){
this.set("loading", true);
this.get("pages."+route).loadComponent((component) => {
this.components.Page = component.Component;
this.set("loading", false);
});
}
});
},
data: {
pages: {
"#hello": {
name: "Hello",
loadComponent: (callback) => {
require.ensure([], () => {
callback(require("./page_component/hello/hello.js"));
});
}
},
"#world": {
name: "World",
loadComponent: (callback) => {
require.ensure([], () => {
callback(require("./page_component/world/world.js"));
});
}
},
"#activity": {
name: "Individual Activity",
loadComponent: (callback) => {
require.ensure([], () => {
callback(require("./page_component/individual_activity/assets/js/src/main.js"));
});
}
}
}
}
I have gotten this working fabulously, with one caveat. I'm using ES6, and the babel-loader to load it. The modules containing the functionality, templates, styles etc. for the tabs all have to be directly contained within the directory structure of the app, like so (see: page_components directory):
├── assets
│ ├── css
│ ├── js
│ │ ├── main.js
│ │ └── page_components
│ │ ├── hello
│ │ ├── individual_activity
│ │ └── world
│ └── templates
│ └── index.html
├── package.json
└── webpack.config.js
I would prefer each page component to be its own package, with a package.json, and included via for example: require("individial_activity"), for purposes of code organization.
The problem is, it appears that webpack doesn't run external modules (such as the modules included via node_modules) through any loader, and as such I get errors about unexpected symbols when trying to load ES6 code.
I tried such things as require("babel-loader!individual_activity") and, require("babel-loader!individual_activity/path/to/main.js") to no avail.
Is what I'm trying to do not the normal way of doing things? Should I keep all my code for all the modules in the same directory structure? Am I doing something blatantly wrong?
webpack.config.js:
var webpack = require("webpack");
module.exports = {
entry: ['./assets/js/main.js'],
output: {
path: './build',
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.css$/,
exclude: /node_modules/,
loader: "style-loader!css-loader"
}
]
},
resolve: {
modulesDirectories: ['node_modules', 'bower_components'],
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
dead_code: true,
conditionals: true,
unsafe: false,
warnings: false
},
mangle: false
}),
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en.js/)
]
};
Thanks!
It's a nice idea to keep your concerns separate, but I think you'd be going overkill by making each section of your app an npm package. Allow npm to handle external dependancies and one off libraries, not highly dependent parts of your application.
If all you are looking for is cleaner require() statements, try adding your js directories to your modulesDirectories config:
resolve: {
modulesDirectories: ['node_modules',
'bower_components',
'assets/js',
'assets/js/page_components'],
},
Should then allow you to require modules directly inside page_components without the need for a path or extension, e.g. require('individual_activity')