Webpack : config npm modules load - angularjs

I'm new with webpack and I didn't find a way to load my vendor libs from node_modules with their dependencies (order and main files [js, css]) into a separate bundle file.
I used to work with bower_components but according to this documentation I moved to npm.
Example
I have angular material in my system that depends on angular and his own css file (angular-material.css).
What did I try already
I used the webpack.optimize.CommonsChunkPlugin which did load the venodors js files, but in the order that I entered in the configuration file (see config file attached below) so if I would have put angular material before angular the run would fail.
I tried configuring the resolve object to read from the "bower.json" which has a main files description and dependencies configured in it but that didn't work as well.
My config file
let webpack = require("webpack");
let path = require("path");
// define preprocessor variables
const envOptions = {
NODE_ENV: "development",
DEBUG: true,
isProduction: false
};
// pass as JSON object into query string ?json=...
const envJson = require('querystring').encode({json:JSON.stringify(envOptions)});
module.exports = {
context: __dirname + "/app",
entry: {
app: "./app.ts",
vendor: [
"jquery",
"angular-animate",
"angular-aria",
"angular-messages",
"angular-resource",
"angular-sanitize",
"angular-ui-router",
"angular-cache",
"angularjs-toaster",
"angular-translate",
"angular-translate-handler-log",
"angular-translate-loader-static-files",
"angular-material",
"angular",
"angular-dynamic-locale",
"ng-file-upload",
"angular-permission",
"moment",
"angular-moment",
"angular-hotkeys",
"angular-scroll",
"jquery.scrollbar",
"lodash",
"ag-grid",
"angular-ui-tree"],
},
output: {
filename: "bundle.js"
},
module: {
loaders: [
{ test: /\.ts/, loader: ['ts-loader?transpileOnly=true', `ifdef-loader?${envJson}`], exclude: [nodeModulesDir], }
]
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery" : "jquery",
"moment": "moment",
"agGrid": "ag-grid"
}),
new webpack.optimize.CommonsChunkPlugin(
{ name: 'vendor', filename: 'vendor.bundle.js' , test: 'node_modules/'}
)
],
resolve:{
modules: ['node_modules'],
extensions: ['.ts','.js', '.css', '.scss'],
},
devtool: "#source-map"
};
What do I want to achieve
Webpack will generate 2 bundles:
vendor.bundle.js - a file that contains all the vendor main js
files in the correct loading order.
app.bundle.js - a file that contains all of my app's inner files.
vendor.bundle.css - a file with all the vender main css files
both vendor bundles should be as defined as in the bower.json dependencies.
My Webpack version is 2.1.0-beta.25

Related

Webpack build for exisitng AngularJS project

I am looking to migrate the existing Ruby based build system in our AngularJS(1.4.X) project to Webpack. The project code is not using JS modules and being with old-school Angular code patter I am not sure how Webpack will find all the controller and factory files in the project.
Folder structure is like,
-app
- assets
- javascripts
- ctrl
- controllerA.js
- controllerB.js
-services
-serviceA.js
-serviceB.js
- angular.min.js
- angular-route.js
- main.js
Wen I use the main.js in my entry point it get copied into the build folder but none of the other files as processed by Webpack even if I use babel-loader to .js rule.
One option I can think of is to use all other files into a separate bundle file using something like
https://www.npmjs.com/package/webpack-merge-and-include-globally, but I want to know whether there is a better way of doing it.
My current webpack config is as below.
module.exports = {
context: __dirname +'/app',
entry: {
'app-portal': [
'/assets/javascripts/main.js',
'/assets/javascripts/angular.min.js',
'/assets/stylesheets/portal/style.css',
'/assets/stylesheets/portal/navbar.css',
'/assets/stylesheets/portal/animation.css',
'/assets/stylesheets/portal/bootstrap.min.css',
'/assets/stylesheets/portal/bootstrap-notify.css',
'/assets/stylesheets/portal/fontello.css',
]
},
output: {
path: __dirname + "/dist/assets",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader:'css-loader',
options: {
sourceMap: true,
url: false,
},
},
],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './views/portal/index.html',
filename: '../index.html',
}),
new MiniCssExtractPlugin({
filename: './[name].css',
linkType: false,
ignoreOrder: false,
}),
new CopyPlugin({
patterns: [
{
from: './views/portal/**/*.*',
to: "../[name].[ext]",
globOptions: {
ignore: [
'**/index.*',
],
},
},
{
from: './assets/fonts/*.*',
to: "./[name].[ext]",
},
{
from: './assets/images/portal/*.*',
to: "./[name].[ext]",
},
{
from: './assets/theme/*.*',
to: "./[name].[ext]",
}
]
}),
],
Probably Webpack is not the right solution for me as I don;t want to change the source code as suggested in Webpack plugins and/or strategies for AngularJS
You can try something like this (we use it for running tests):
bundle.js:
const jsConext= require.context('.', true, /\.js/);
ng1Context.keys().forEach(ng1Context);
const cssConext= require.context('.', true, /\.css/);
ng1Context.keys().forEach(ng1Context);
...
entry: { 'app-portal': 'bundle.js' }
This should work in general (You might need fix order for css or in case of multiple angular modules etc.)

How to use plugin to reduce size when import lodash

Here is my code : import _ from 'lodash';
I want to use babel-plugin-transform-imports to reduce size of folder when "yarn build".
But I don't know how to set up plugin and config in wepack.config.js
Thank you so much
There is three way to reduce:
1. When in development, you can include the folder where you are going to compile by config the loaders, so the file outside this folder won't be compiled. Loader config are like the following code:
{
test: /\.(js|mjs|jsx)$/,
include: path.resolve(__dirname,"src"),//important
use: {
loader: 'babel-loader'
}
}
2、 You can use DDL to pre-compile the third-party library.
e.g.
Firstly create vendor.js, that is to say you need to bundle it by another webpack config.
const webpack = require('webpack')
const library = '[name]_lib'
const path = require('path')
module.exports = {
mode:"production",
entry: {
vendors: ['lodash']
},
output: {
filename: '[name].dll.js',
path: path.join(__dirname,"dist/vendor"),
library
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, 'dist/[name]-manifest.json'),
// This must match the output.library option above
name: library
}),
]
}
And then you need to include mainfest.json in your project webpack config:
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: path.join(__dirname, 'dist/vendors-manifest.json'),
})
]
3、 You can use externals to exclude it, you can config it like:
externals : {
lodash : {
commonjs: 'lodash',
amd: 'lodash',
root: '_' // indicates global variable
}
}
And don't forget to include lodsh script in HTML, because webpack don't compile or include it in your bundle. If you don't include ,the broswer will throw an error.
You can check more usage at Webpack website:
https://webpack.js.org/configuration/externals/
https://webpack.js.org/plugins/dll-plugin/

How to include node_modules using webpack?

In my angularJs 1.3 application, earlier I was using bower and grunt and it was working fine. I was adding files in my index.html like the following screenshot. But now I have installed all the packages using NPM and using WEbPack 4.21.0 for bundling and run the application. But now if I remove the packages link from Index.html file my application stops working. But I don't want all those links in Index.html and just want to generate a bundle file from those files. Kindly guide me how can I achieve this? Currently, its just adding angular.js file and few other files in vendor.js.
Index.html
Package.json
webpack.config.js
Updated Question:
Now i am using following webpack.config.js but its creating bootstrap_and_some_plugin.css.js . It has to create css file but don't know why it's creating js file?
module.exports = {
context: __dirname + '/app/scripts',
resolve: {
modules: ['bower_components', 'node_modules'],
alias: {
bower_components: __dirname + '/app/bower_components',
assets: __dirname + '/app/assets'
},
extensions: ['.js', '.jsx', '.css']
},
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" }
]
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}]
}
]
},
entry: {
app: './main-app.js',
'bootstrap_and_some_plugin.css': [
'bower_components/font-awesome/css/font-awesome.css',
'bower_components/seiyria-bootstrap-slider/dist/css/bootstrap-slider.min.css',
'bower_components/angular-ui-tree/dist/angular-ui-tree.min.css',
]
},
output: {
filename: '[name].js',
path: __dirname + '/app/scripts',
//chunkFilename: '[id].[chunkhash].js',
},
devServer: {
contentBase: './app',
host: 'localhost',
port: '9000',
inline: true,
compress: true,
proxy: {
'/api/**': {
//target: 'http://10.189.1.159:8080',
target: 'http://localhost:9100',
secure: false,
changeOrigin: true,
cookieDomainRewrite: true
}
},
open: true
},
plugins: [
]
};
In the file webpack.config.js, you add this property inside the resolve property:
resolve: {
alias: {
bower_components: __dirname + '/app/bower_components'
}
}
In the file main-app.js, if you want to use some js file, you call like this:
require('bower_components/jquery/dist/jquery.js');
require('bower_components/angular/angular.js');
require('bower_components/bootstrap/dist/js/bootstrap.js');
// ...
You need to specify the path of the file webpack.config.js. In my example, all the path looks like:
your_project
webpack.config.js
app
bower_components
jquery
...
angular
...
bootstrap
...
__dirname refers to the current path of the js file which is using it. If you use __dirname inside the webpack.config.js file, it will render your_project. Or using it inside jquery.js, it will render your_project\app\bowser_components\jquery\dist.
Then, build to bundle.js file and delete all the path in the Index.cshtml file.
Hope this helps!
UPDATE: If your js target file goes too big. You can split modules to multiple parts, like this:
entry: {
'bootstrap_and_some_plugin.css': [
'./app/bower_components/bootstrap/dist/css/bootstrap.min.css',
'./app/bower_components/some-plugin/css/some-plugin.css'
],
'jquery_and_angular.js': [
'./app/bower_components/jquery/dist/jquery.js',
'./app/bower_components/angular/angular.js'
],
'site.js': ['./js/site']
}
Then, in your Index.cshtml:
<link href="bootstrap_and_some_plugin.css" rel="stylesheet" />
<!-- body content -->
<script src="jquery_and_angular.js"></script>
<script src="site.js"></script>
UPDATE 2: You need to install the 2 packages babili-webpack-plugin and extract-text-webpack-plugin
In the file webpack.config.js:
// define these variables before "module.exports"
var BabiliPlugin = require('babili-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {...};
Then, setting the pluggin options:
plugins: [
new BabiliPlugin({}, { test: /\.js$/, comments: false }),
new ExtractTextPlugin('[name]'),
... and other options
]
and the output options:
output: {
filename: '[name]',
... and other options
}

How to build unified $templateCache when migrating AngularJS 1.x project from gulp & bower to webpack 3

Have a large AngularJS 1.6 project (~120 JS files), which is currently built through gulp/bower.
Looking to migrate over to using yarn & webpack, and we would prefer not to have to modify our project files just to implement webpack. Each of our AngularJS component JS files are wrapped in a IIFE, so they are already out of the global scope.
One of our gulp steps uses the gulp-angular-templatecache module, which collects all of our HTML files and neatly compacts them into a single $tmplateCache loader module.
angular.module("ourApp").run(["$templateCache", function ($templateCache) {
$templateCache.put("/app/components/ourComponent1.html", "<div id=\"component1-html\"> ... </div>\r\n");
$templateCache.put("/app/components/ourComponent2.html", "<div id=\"component2-html\"> ... </div>\r\n");
// etc...
});
I have managed to figure out how to resolve most of our other build processes using webpack, but this one is giving me a problem.
I have looked at the ngtemplate-loader package, but do not think this would work for our needs because of the following:
Would require us to update all of our existing HTML templates to use 'require("./template.html")'
This would create a separate webpack module for each HTML template, which seems very inefficient.
Probably most important, I haven't been able to get it to work.
The current webpack configuration I have setup is based on a simple demo, and splits the project files out from the vendor files. Our project files are bundled up into a 'app.[hashcode].js' file into the /dist folder.
Ultimately, I would like to be able to inject the compiled $templateCache module, into a specific point in our final 'app.[hashcode].js' bundle file. However, right now I would be satisfied with the $templateCache definition file being created into a separate bundle file.
Is there an existing webpack plugin, or loader, or combination of plugin(s)/loader(s), that I could use to accomplish this build step? Is this even possible with webpack?
This is the base directory structure for the demo project:
/dashboard
/app
/assets
/global
global.less
app.less
/components
/controllers
dashboard.controller.js
/directives
yep-nope.directive.js
/messenger
messenger.directive.js
messenger.html
/services
github-status.service.js
dashbboard.config.js
dashboard.module.js
app.js
/dist
app.4f12bb49f144e559bd9b.js
assets.css
index.html
vendor.b0a30c79aa77e0126a5c.js
index.html
package.json
webpack.config.js
This is the current working webpack.config.js file:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
context: __dirname,
entry: {
app: path.resolve(__dirname, 'app/app.js'),
vendor: ['angular','angular-sanitize']
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
module: {
rules: [
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ['css-loader', 'less-loader']
})
},
{
test: /\.js$/,
loader: 'ng-annotate-loader'
},
{
test: /\.html$/,
exclude: path.resolve(__dirname, 'app/index.html'),
use: [
{ loader: 'html-loader', options: { minimize: false } }
]
}]
},
plugins: [
new CleanWebpackPlugin(['dist','assets/**/*.css']),
new HtmlWebpackPlugin({
title: 'GitUp',
template: 'index.html',
inject: 'body'
}),
new webpack.optimize.CommonsChunkPlugin({
name:"vendor", filename:"[name].[chunkhash].js"
}),
new ExtractTextPlugin('assets.css')
]
};
This is the webpack 'entry' file app/app.js:
require('./assets/app.less');
require('../node_modules/angular/angular.js');
require('../node_modules/angular-sanitize/angular-sanitize.js');
require('./components/dashboard.module.js'); // Define module
require('./components/dashboard.config.js'); // Setup config
// Load in all components files, except for files already loaded above
var reqCtx = require.context('./components', true, /^(?!.*(?:dashboard\.config|dashboard\.module)).*\.js$/);
reqCtx.keys().forEach(reqCtx);
If needed, I can provide the entire sample project...
This may or may not be the answer you're looking for but in the past I've used html-loader to allow me to require my component template URLs, and it worked brilliantly:
https://www.npmjs.com/package/html-loader
It just inlines the template in your bundled script.

jQuery requires a window with a document in webpack

I'm using ReactJS.net (server-side render) and when I use jquery in Webpack then I got error
here is my error
Error while rendering "Components.ToDoListSkeleton" to
"react_0LmYYfSk30qdrKJQe4McUQ": Error: jQuery requires a window with a
document
at module.exports (Script Document [5]:51:87) -> module.exports=global.document?factory(global,true):function(w){if(!w.document){throw
new Error("jQuery requires a window with a document");}return
factory(w);};}else {factory(global);} // Pass this if window is not
defined yet
at new ToDoListSkeleton (Script Document [5]:26:903)
at ReactCompositeComponentMixin._constructComponentWithoutOwner (Script Document [2]:8271:28)
at ReactCompositeComponentMixin._constructComponent (Script Document [2]:8253:22)
at ReactCompositeComponentMixin.mountComponent (Script Document [2]:8172:22)
at ReactReconciler.mountComponent (Script Document [2]:1977:36)
at Script Document [2]:19549:37
at Mixin.perform (Script Document [2]:3788:21)
at renderToStringImpl (Script Document [2]:19544:25)
at renderToString (Script Document [2]:19574:11)
at Script Document [7] [temp]:1:16 Line: 19549 Column:37
here is my webpack config
"use strict";
var path = require('path');
var WebpackNotifierPlugin = require('webpack-notifier');
var webpack = require("webpack");
module.exports = {
context: path.join(__dirname, 'Content'),
entry: {
server: './server'
},
output: {
path: path.join(__dirname, 'build'),
filename: '[name].bundle.js'
},
module: {
loaders: [
// Transform JSX in .jsx files
{ test: /\.jsx$/, loader: 'jsx-loader?harmony' },
{ test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" }
]
},
resolve: {
// Allow require('./blah') to require blah.jsx
extensions: ['', '.js', '.jsx']
},
externals: {
//// Use external version of React (from CDN for client-side, or
//// bundled with ReactJS.NET for server-side)
react: "React"
},
plugins: [
new WebpackNotifierPlugin(),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
})
]
};
Any help or suggestions would be appreciated, Thanks.
jQuery is only designed for use in a browser, and does not support server-side rendering. You'll need to remove jQuery from any of your code that you want to use server-side.

Resources