How to create Javascript library OOP and build bundle with Webpack? - javascript

I try to create a Javascript library with OOP style and make it can run with the browser. I am a newbie to modern javascript.
My Example Code:
mylib.js
function MyLib() {
if (!(this instanceof MyLib)) {
return new MyLib(options)
}
this.init(options);
return this
}
MyLib.prototype.init = function (options) {
this.debug = options.debug
console.log(options)
}
.... ///
export default MyLib
index.js
import MyLib from './mylib.js';
index.html
<script src="dist/mylib.js"></secript>
<script>
let mylib = new({
debug: true
});
</script>
webpack.config.js
const webpack = require('webpack')
const path = require('path')
module.exports = {
entry: {
mylib: './lib/index.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
},
mode: process.env.MINIFY_BUILD ? 'production' : 'development',
plugins: [
new webpack.DefinePlugin({
'procrss.env.NODE_ENV': 'production'
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules\/(?!(lit-element|lit-html)\/).*/,
loader: 'babel-loader'
}
]
}
}
So after all, I got an error message like below
Uncaught ReferenceError: MyLib is not defined
Please help or suggest to me.

Related

Wrong URL for images with React + Typescript + WebPack

I'm referencing an image inside my .JSX file but the generated URL is wrong.
It looks like this : http://localhost:43124/dist/dist/9ee7eb54c0eb428bb30b599ef121fe25.jpg
The folder "dist" exists with the picture but not "dist/dist". I think the problem comes from my Webpack.config.js. Here are the files :
module.d.ts
I instruct Typescript what to do with image files as mentionned here.
declare module '*.jpg'
declare module '*.svg'
Layout.tsx
I reference my logo inside React so it can be packed by Webpack.
/// <reference path="./module.d.ts"/>
import * as React from 'react';
import logo from '../img/logo.svg';
export class Layout extends React.Component<{}, {}> {
public render() {
return <img src="{logo}" width="220" alt="logo" />
}
}
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const merge = require('webpack-merge');
module.exports = (env) => {
const isDevBuild = !(env && env.prod);
// Configuration in common to both client-side and server-side bundles
const sharedConfig = () => ({
stats: { modules: false },
resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.tsx?$/, include: /ClientApp/, use: 'awesome-typescript-loader?silent=true' },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
});
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig(), {
entry: { 'main-client': './ClientApp/boot-client.tsx' },
module: {
rules: [
{ test: /\.css$/, use: ExtractTextPlugin.extract({ use: isDevBuild ? 'css-loader' : 'css-loader?minimize' }) }
]
},
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new ExtractTextPlugin('style.css'),
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin()
])
});
return [clientBundleConfig];
};
I used the default Visual Studio ASP.NET Core React + Redux template.

webpack - output.filename error

I know this is a common question for webpack; it's really hard to debug something if it won't give you any information about the cause or location of the error.
I'm getting the error:
Error: 'output.filename' is required, either in config file or as --output-filename
I know it has to do with a syntax error somewhere, but I'm too new to webpack to figure it out.
Here's my config file. It's called "webpack.config.js" in the root folder (i.e. the folder in which I initially ran: npm init).
const webpack = require('webpack');
const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin")
const RewriteImportPlugin = require("less-plugin-rewrite-import");
const root_dir = path.resolve(__dirname)
const src_dir = path.resolve(__dirname, "webpack_src")
const build_dir = path.resolve(__dirname, "webpack_bin")
const node_mod_dir = path.resolve(__dirname, 'node_modules');
const extractLESS = new ExtractTextPlugin('style.css');
const config = {
entry: {
index: path.resolve(src_dir, 'index.js')
},
output: {
path: build_dir,
filename: 'bundle.js'
},
resolve: {
modules: [root_dir, 'node_modules'],
},
module: {
rules: [
{
loader: 'babel-loader',
test: /\.(js)$/
},
{
use: extractLESS.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'less-loader',
options: {
paths: [root_dir, node_mod_dir],
plugins: [
new RewriteImportPlugin({
paths: {
'../../theme.config': __dirname + '/semantic_ui/theme.config',
}
})
]
}
}]
}),
test: /\.less$/
},
{
use: ['file-loader'],
test: /\.(png|jpg|gif|woff|svg|eot|ttf|woff2)$/
},
]
},
plugins: [
extractLESS,
new webpack.optimize.ModuleConcatenationPlugin()
]
};
module.exports = {
config
};
You're exporting module.exports = { config }, which means that you are exporting an object with one property, namely config, but webpack expects the object to be your entire config. Webpack requires output.filename, whereas you only provide config.output.filename.
The export should be your config:
module.exports = config;

Webpack throws TypeError: Super expression must either be null or a function, not undefined when importing LESS file

I have the following in a file initialize.js:
import App from './components/App';
import './styles/application.less';
document.addEventListener('DOMContentLoaded', () => {
const app = new App();
app.start();
});
In webpack.config.js I have:
'use strict';
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const ProvidePlugin = webpack.ProvidePlugin;
const ModuleConcatenationPlugin = webpack.optimize.ModuleConcatenationPlugin;
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const extractLess = new ExtractTextPlugin({
filename: 'app.css',
});
const webpackCommon = {
entry: {
app: ['./app/initialize']
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader?presets[]=es2015'
}]
}, {
test: /\.hbs$/,
use: {
loader: 'handlebars-loader'
}
}, {
test: /\.less$/,
exclude: /node_modules/,
use: extractLess.extract({
use: [{
loader: 'css-loader'
}, {
loader: 'less-loader'
}],
// use style-loader in development
fallback: 'style-loader'
}),
}]
},
output: {
filename: 'app.js',
path: path.join(__dirname, './public'),
publicPath: '/'
},
plugins: [
extractLess,
new CopyWebpackPlugin([{
from: './app/assets/index.html',
to: './index.html'
}]),
new ProvidePlugin({
$: 'jquery',
_: 'underscore'
}),
new ModuleConcatenationPlugin(),
],
};
module.exports = merge(webpackCommon, {
devtool: '#inline-source-map',
devServer: {
contentBase: path.join(__dirname, 'public'),
compress: true,
port: 9000
}
});
I tried removing the the plugins and the contents of application.less, but I keep getting this error:
ERROR in ./node_modules/css-loader!./node_modules/less-loader/dist/cjs.js!./app/styles/application.less
Module build failed: TypeError: Super expression must either be null or a function, not undefined
at ...
# ./app/styles/application.less 4:14-127
# ./app/initialize.js
If I replace that LESS file with a CSS one and update the config it works fine, so I guess the problem has to do with less-loader.
I'm using Webpack 3.4.1, Style Loader 0.18.2, LESS Loader 4.0.5, Extract Text Webpack Plugin 3.0.0 and CSS Loader css-loader.
My bad, I didn't notice I was using an old less version. That was the culprit. Just updated it to 2.7.2 and the problem is gone.

ES6 import of AMD (e.g. jQuery 3.1.1) module in webpack 2

I'm doing some testing with the latest and greatest webpack 2 version and came across a problem when trying to import jQuery 3.1.1 as a dependency.
I simply used import {$} from 'jquery'; to import but the resulting bundle generated an exception TypeError: __webpack_require__.i(...) is not a function when executed.
Using const $ = require('jquery'); works as expected.
It was my understanding that with webpack 2 I'm allowed to use es6 imports (almost) independently of the format of the library.
webpack.config.js:
'use strict';
const path = require('path');
const webpack = require('webpack');
function config(env) {
const PRODUCTION = env && typeof env.production !== 'undefined';
const PLUGINS = [
new webpack.DefinePlugin({
DEVELOPMENT: JSON.stringify(!PRODUCTION),
PRODUCTION: JSON.stringify(PRODUCTION)
})
];
if (PRODUCTION) {
PLUGINS.push(new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
dead_code: true,
unused: true,
}
}));
}
return {
entry: {
index: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.js$/i,
include: /src/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
compact: false,
presets: [['es2015', {modules: false}]]
}
}
]
}
]
},
plugins: PLUGINS,
devtool: 'source-map'
};
}
module.exports = config;
Two questions:
Is this a bug or just not intended to work as I would expect it?
What error does the exception TypeError: __webpack_require__.i(...) is not a function generally indicate?
My mistake: I've used a named import instead of the default import.
Correct:
import $ from 'jquery';
Wrong:
import {$} from 'jquery';

What is the best practice for importing angularjs using webpack?

How do you use Webpack and AngularJS together, and how about template loading and on demand fetching of resources?
An example of a well written webpack.config.js file for this purpose would be very much appreciated.
All code snippets displayed here can be accessed at this github repo. Code has been generously adapted from this packetloop git repo.
webpack.config.json
var path = require('path');
var ResolverPlugin = require("webpack/lib/ResolverPlugin");
var config = {
context: __dirname,
entry: ['webpack/hot/dev-server', './app/app.js'],
output: {
path: './build',
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.css$/,
loader: "style!css-loader"
}, {
test: /\.scss$/,
loader: "style!css!sass?outputStyle=expanded"
}, {
test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/,
loader: "file"
}, {
test: /\.html$/,
loader: "ngtemplate?relativeTo=" + path.join(__dirname, 'app/') + "!raw"
}]
},
// Let webpack know where the module folders are for bower and node_modules
// This lets you write things like - require('bower/<plugin>') anywhere in your code base
resolve: {
modulesDirectories: ['node_modules', 'lib/bower_components'],
alias: {
'npm': __dirname + '/node_modules',
'vendor': __dirname + '/app/vendor/',
'bower': __dirname + '/lib/bower_components'
}
},
plugins: [
// This is to help webpack know that it has to load the js file in bower.json#main
new ResolverPlugin(
new ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
)
]
};
module.exports = config;
To import AngularJS into the main app.js you do the following:
app/vendor/angular.js
'use strict';
if (!global.window.angular) {
require('bower/angular/angular');
}
var angular = global.window.angular;
module.exports = angular;
And then use it in app.js like so,
app.js
...
var angular = require('vendor/angular');
// Declare app level module
var app = angular.module('myApp', []);
...
Is the following correct? Is there an easier way to do this? I've seen a few (not a lot by any standards) posts which listed another method.
From this reddit post comment
// Add to webpack.config.js#module#loaders array
{
test: /[\/]angular\.js$/,
loader: "exports?angular"
}
There is also another plugin which is in development right now, at stackfull/angular-seed. It seems to be in the right direction, but is really really hard to use right now.
Webpack is way awesome, but the lack of documentation and samples are killing it.
You can just require angular in all modules (files) where you need it. I have a github repository with example how to do that (also using webpack for build). In the example ES6 import syntax is used but it shouldnt matter, you can use standard require() instead.
Example:
import 'bootstrap/dist/css/bootstrap.min.css';
import './app.css';
import bootstrap from 'bootstrap';
import angular from 'angular';
import uirouter from 'angular-ui-router';
import { routing} from './app.config';
import common from './common/common.module';
import featureA from './feature-a/feature-a.module';
import featureB from './feature-b/feature-b.module';
const app = angular
.module('app', [uirouter, common, featureA, featureB])
.config(routing);
I am starting with Angular + Flux with Webpack so may be I can help you with some things.
Basically I am installing everything with NPM, it has module export system, so it works like nothing. (You can use export-loader, but why if you do not need to.)
My webpack.config.js looks like this:
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require("html-webpack-plugin");
var nodeModulesDir = path.resolve(__dirname, './node_modules');
// Some of my dependencies that I want
// to skip from building in DEV environment
var deps = [
'angular/angular.min.js',
...
];
var config = {
context: path.resolve(__dirname, './app'),
entry: ['webpack/hot/dev-server', './main.js'],
resolve: {
alias: {}
},
output: {
path: path.resolve(__dirname, './build'),
filename: 'bundle.js'
},
// This one I am using to define test dependencies
// directly in the modules
plugins: [
new webpack.DefinePlugin({
ON_TEST: process.env.NODE_ENV === 'test'
})
],
module: {
preLoaders: [
{test: /\.coffee$/, loader: "coffeelint", exclude: [nodeModulesDir]}
],
loaders: [
{test: /\.js$/, loader: 'ng-annotate', exclude: [nodeModulesDir]},
{test: /\.coffee$/, loader: 'coffee', exclude: [nodeModulesDir]},
...
],
noParse: []
},
devtool: 'source-map'
};
if (process.env.NODE_ENV === 'production') {
config.entry = {
app: path.resolve(__dirname, './app/main.js'),
vendors: ['angular']
};
// config.output.path = path.resolve(__dirname, './dist');
config.output = {
path: path.resolve(__dirname, "./dist"),
filename: "app.[hash].js",
hash: true
};
config.plugins.push(new webpack.optimize.UglifyJsPlugin());
config.plugins.push(new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.[hash].js'));
config.plugins.push(new HtmlWebpackPlugin({
title: 'myApp',
template: path.resolve(__dirname, './app/index.html'),
inject: 'body'
}));
delete config.devtool;
}
else {
deps.forEach(function (dep) {
var depPath = path.resolve(nodeModulesDir, dep);
config.resolve.alias[dep.split(path.sep)[0]] = depPath;
config.module.noParse.push(depPath);
});
}
module.exports = config;
My main.js looks like this:
var angular = require('angular');
if(ON_TEST) {
require('angular-mocks/angular-mocks');
}
require('./index.coffee');
And index.coffee containt main angular module:
ngModule = angular.module 'myApp', []
require('./directive/example.coffee')(ngModule)

Categories