How to pass externals from webpack to jest? - javascript

I've got this webpack config as part of my grunt building process:
module.exports = {
options: {
output: {
path: path.resolve('../ui/static/js'),
filename: '[name].js',
chunkFilename: '[id].[name].js',
libraryTarget: 'amd',
library: '[name]'
},
externals: [
'jquery',
'lodash',
'backbone',
'backbone.layoutmanager',
'moment',
'spin',
'lib/select2.min',
'dispatcher'
],
resolve: {
root: path.resolve('../ui'),
alias: {
'jst': 'static/jst'
}
}
We are moving to react now, and I need to import some files in my test files, where this dependencies included, but jest can not find them:
Cannot find module 'lib/select2.min' from 'helpers.js'
Cannot find module 'jst/templates_jst' from 'base-view.js
What is the right way to resolve this issue?

Here's what works today with webpack#4.11.1 and jest#23.1.0. Assuming this is your externals webpack config:
externals: {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react',
},
}
You'll need to map each external library to be properly resolved in your jest config like so:
moduleNameMapper: {
"^./react": path.resolve(__dirname, 'node_modules/react'),
}
While debugging your issue, be sure to check what your built component file looks like. You want to be sure that you see something like:
!function(e,t){if("object"==typeof exports&&"object"==typeof module)
module.exports=t(require("react"));
else if("function"==typeof define&&define.amd)define(["react"],t);
else{var n="object"==typeof exports?t(require("react")):t(e.React);
Important bit being react for commonjs and amd, and React for the browser.

You need to mock the external lib.
Example with jquery:
Create a __mocks__ folder in the same level of __test__ folder.
Inside that, create a file with the same name of the dependency, in this case, jquery (jquery.js).
Inside the test file, use jest.mock function to reference the mock external dependency: jest.mock('jquery');
from jest the docs:
https://facebook.github.io/jest/docs/manual-mocks.html
Hope it helps.

For my case using the __mocks__ would be a bit verbose but I used the
jest.mock('myModule', () => {/* module impl */}, {virtual: true})
In case the __mocks__ suggestion is to verbose for you too check out the docs here

Related

Webpack alias in Laravel Mix to node_modules

I would like to use an alias in VUE.JS in a Laravel 5.8 project to import css and js I have in my module.
webpack.mix.js
mix.webpackConfig({
resolve: {
alias: {
'alias': path.resolve(
__dirname,
'~myModule/src'
)
}
}
});
In my VUE App.js I would like import the css folder and I wrote:
resources/js/app.js
// css files
import 'alias/lib/css'
// js files
import 'alias/lib/script'
But I'm wrong something becouse the alias is not resolved:
ERROR in ./resources/js/app.js
Module not found: Error: Can't resolve 'alias/lib/css' in...
Can you help me to fix the issue?
After so many attempts I got the issue. The code was good but I was missing to load the webpack.mix.js properly:
From Laravel Mix documentation:
The webpack.mix.js file is your entry point for all asset compilation. Think of it as a light configuration wrapper around Webpack. Mix tasks can be chained together to define exactly how your assets should be compiled.
But if you are using npm run watch it is not (re)loaded before to compile new changed assets. This means:
if you are in watch mode (npm run watch) exit and restart it to load new updated webpack.config.js if you changed it.
Finally it worked! And it resolve new alias properly!
Here the final config I used in webpack.config.js:
mix.webpackConfig({
resolve: {
alias: {
'aliasName': path.resolve(
__dirname,
'node_modules/MyModule/src/'
)
}
}
});
Another alternative is:
mix.webpackConfig({
resolve: {
modules: [
'node_modules'
],
alias: {
'aliasName' : 'MyModule/src/'
}
}
});
Then in my Vue component (or in vue app.js, just in case)
<template>
<myModule-component></myModule-component>
</template>
require('aliasName/lib/css'); // to load full css directory
require('aliasName/lib/script'); // to load full js directory
import MyModuleComponent from 'aliasName/widgets/MyModuleComponent.vue'
...
export default {
...
components: {
'myModule-component': MyModuleComponent
}

Can I have a common .env file for my app and its dependency?

I did something like this:
root/
node_modules/
myPackage/
index.js // uses the .env, can access process.env
app.js // uses the .env, can access process.env
.env
In app.js, the process object is a global, when I import myPackage the global object is also available in myPackeg/index.js. All good, hurray.
But, the node_modules/myPackage is not bundled, its just a couple of .js files with entry point at index.js. If myPackege is run through webpack build (minified, mangled) it somehow no longer is able to inherit the global process object from app.js. I don't understand why.
Webpack config of myPackage is nothing special, compiles to ES5, UMD. The code was mangled though, I excluded the 'process' from being mangled but it didn't help.
What am I missing?
webpack.config.js (without transplanting to ES5 with Babel)
module.exports = {
mode: 'production',
entry: './lib/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'myModule',
library: 'myModule',
libraryTarget: 'umd',
},
resolve: {
alias: {
lodash: path.resolve(__dirname, 'node_modules/lodash'),
'bn.js': path.resolve(__dirname, 'node_modules/bn.js'),
},
},
node: {
Buffer: false,
},
};

webpack bundle size vs requirejs bundle size

I'm trying to migrate a requireJS based app to webpack.
This app doesn't have many dependencies - actually it only needs a promise polyfill - and I've already figured out how to make webpack using the minified one.
The bundle size with requireJS used to be 43KB, when using webpack it's 121KB.
While 121KB isn't really huge it is a notable size increase.
From running webpack --display-reasons --display-modules I have learned that there seems to be some node_module dependencies included in my bundle. Way more than I expected.
I see things like buffer, readable-stream, stream-http, stream-browserify, core-util-is, buffer-shims, ...
Is this expected / part of the webpack wrapper code?
Is there anything I can do to exclude these dependencies?
This is my webpack.config.js:
var webpack = require('webpack');
module.exports = {
entry: {
"mynexuz": "./js/mynexuz-api.js",
"kws": "./js/kws-api.js",
"main": "./js/main.js",
"quest": "./js/quest.js"
},
output: {
filename: "./dist/[name]-bundle.js",
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
}
})
],
node: {
//stream: false,
//process: false,
//global: false
},
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
modules: ['js', 'js/lib', 'node_modules'],
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".webpack.js", ".web.js", ".ts", ".tsx", ".js"]
},
module: {
loaders: [
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{
test: /\.js$/,
loader: "source-map-loader",
exclude: /node_modules/
},
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader",
exclude: /node_modules/
}
]
},
};
This doesn't work for all libraries you are using, but when possible you can save on file size by only importing the actual function/component you need to use.
Here is an example with lodash
import has from 'lodash/has';
That way above will ONLY import the has method.
However if you do either of the following:
import { has } from 'lodash';
Or
import _ from 'lodash';
Then you will import ALL of the lodash library which will bump up your file size.
However with other libraries (i.e. current version of moment.js) it's not so simple to import just the PART of the library you need.
There are a few other ways to try to solve this problem (i.e. tweaking your webpack settings) but I would start with this method.
After looking deeper into the issue I've found the reason for the large size of the bundle. In true requireJS style I had:
define(['http', 'config'], function (Http, Config) { ... });
This 'http' thing was supposed to refer to my own library, but webpack resolved this to some NPM module, bringing in all the aforementioned dependencies.
I've now changed the code to:
define(['./http', 'config'], function (Http, Config) { ... });
And the bundle sizes are back to around 44KB.

How to require webpack generate js file with requirejs?I use vue-cli

I make my project by vue-cli.
vue init webpack vue-demo
cd vue-demo
npm install
npm run dev
Now I want to devolop some components. And i want to use them in requirejs.
webpack config
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
filename: '[name].js',
libraryTarget: 'umd',
library:'senyint'
}
Q1:It generate three files. app.js manifest.js vendor.js
The demo has a Hello.vue . I want to require the js file by what webpack generate.
But I require them,it's undefiend . Why? What's the wrong?
Where I should export ?
Now I export in main.js like this.
import Hello from 'components/Hello'
module.exports = {
Hello
}
Q2:I dont want to package without vue.
So i configure this
externals: {
vue: 'vue'
}
If i do this, when npm run dev show error "Uncaught TypeError: Cannot read property 'config' of undefined"
It cause cant find Vue.
If i configure externals vue how to make it run?
Q1:
Open the javascript file app.js i found
define("senyint", ["vue"], factory);
at this line. The 'senyint' is a package name,webpack generate the js,but it doesnt work.
I modify the code like this
define(["vue"], factory);
Require it and it works. But I dont know why.... I just can resolve this problem;
main.js export .vue components
import Hello from 'components/Hello.vue'
export const scom = {
Hello
}
requirejs config
requirejs.config({
baseUrl: 'js/common',
paths: {
module: '../modules'
},
shim: {
app: {
deps:['vue','manifest','vendor']
}
}
})
requirejs(['module/demo', 'app'], function (demojs, app) {
debugger
console.log(app)
})
Q2:
I builded my project with vue-cli webpack template. (not webpack-simple)
In build directory has 'webpack.base.conf.js' and 'webpack.prod.conf.js'
Modify webpack.prod.conf.js add
externals: {
vue: {
root: 'Vue',
commonjs: 'vue',
commonjs2: 'vue',
amd: 'vue'
}
},
and dont add the code in 'webpack.base.conf.js' .Then npm run build it will package without vue.js .Npm run dev use webpack.base.conf.js ,it will run with vue

Webpack exclude entries for CommonsChunkPlugin

I am trying to set up webpack production configuration. All looks well. However, I realized that while using the commons chunk plugin, it covers all the files in common as expected. What I want to do is, separation of common library modules and common application modules. My config file is :
module.exports = {
entry: {
lib: ["react", "react-dom"],
app: "./ui-v2/app/app.js",
app2: "./ui-v2/app/app2.js"
},
output: {
path: path.join(__dirname, "target/ui/v2"),
filename: "/app/[name].[chunkhash].min.js"
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test: /\.(png|jpg|svg)/,
loader: "file-loader?name=img/[name].[hash].[ext]"
// loaders: ["url", "image-webpack"]
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!autoprefixer-loader!sass-loader", {
publicPath: __dirname
})
},
{
test: /\.(woff|woff2|ttf|eot)$/,
loader: "file-loader?name=fonts/[name].[hash].[ext]"
}
]
},
plugins: [
clean,
new webpack.optimize.CommonsChunkPlugin("common", "app/common.[chunkhash].js"),
new webpack.ProvidePlugin({
React: "react",
ReactDOM: "react-dom",
$: "jquery",
_: "lodash"
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
sourceMap: true
},
mangle: {
except: ["exports", "import", "$", "_", "require", "React", "ReactDOM"]
}
}),
new ExtractTextPlugin("styles/[name].[contenthash].css"),
new Manifest()
]
}
Basically I have 3 modules in the app; app.js, app2.js and a common component user.js.
What I want to achieve is to bundle all library related files like react, react-dom, lodash, etc in a lib bundle, and common application components like user.js in a common bundle. In order to do this, I thought there might be an option to exclude the files that I don't want them to go to "common" file. If I use this output, what is the point for long term caching files for library bundles because whenever I get a common component in my project, they will go into the common bundle and the content hash will be different, but nothing changes in this library files like react, jquery, lodash, etc.
Anyway, what I have at the end of build process is everything still goes into the common bundle and lib has nothing and the file sizes are :
app.<hash>.min.js -> 3.05KB
app2.<hash>.min.js -> 3.05KB
lib.<hash>.min.js -> 165 Bytes (has almost nothing!)
common.<hash>.js -> 678 KB
Is there any way to achieve what I want or what would be the best approach to a production build in similar cases? Thank you!
Its because the first parameter for CommonsChunkPlugin is "common" where it should be "lib". The plugin picks up the entry with a name matching with the value of its first parameter.
A simple example config picked from webpack's wiki -
var webpack = require("webpack");
module.exports = {
entry: {
app: "./app.js",
vendor: ["jquery", "underscore", ...],
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendor", /* filename= */"vendor.bundle.js")
]
};
Note that the "vendor" entry is again specified in CommonsChunkPlugin
You should check out Webpack's DLL Plugin.
https://github.com/webpack/webpack/blob/cb3d8e2097503c7245c5dda5b7a6e9d63421a72b/examples/dll/README.md
With this plugin you bundle up common 3rd party vendor dependencies such as React and friends in a DLL, which is essentially just a JSON Manifest that goes along with your requires wrapped in webpack context and cached to disk.
In your project code, you would have your shared components which depend on React and friends, and you would have your application code which depend on your shared components as well as react and friends.
Your project would incorporate the DLL Reference plugin as you can see here:
https://github.com/webpack/webpack/blob/cb3d8e2097503c7245c5dda5b7a6e9d63421a72b/examples/dll-user/README.md
This will see to it that your shared components and your application code pull React and other 3rd party modules from the same DLL bundle. This can help improve build times and the performance of the dev server and hot module reloading.

Categories

Resources