Object is not defined after Webpack bundling - javascript

I have simple app wrote in ES6 for the training purpose. I want to use modules in this app, so I installed webpack and babel. Unfortunetaly, when I try to fire my method, I receive the error:
Uncaught ReferenceError: gas is not defined
at HTMLButtonElement.count (bundle.js:113)
So, 'gas' is my instance of the object.
Here are my files:
main.js
'use strict'
import Gas from "./gas";
const count = document.getElementById("gas-count");
const gas = new Gas();
count.addEventListener("click", gas.count);
gas.js
export default class Gas {
constructor() {
}
count() {
// code
}
printResult(result) {
// code
}
_isValid(dist, price, aver) {
// Code
}
};
Finally, here is my Webpack config:
module.exports = {
// Define entry point
entry: "./src/main.js",
// Define output point
output: {
path: __dirname + "/dist",
filename: "bundle.js"
},
module: {
loaders: [{
test: /\.js$/,
exclude: /(node_modules)/,
loader: "babel-loader",
query: {
presets: ["env"]
}
}]
}
};
I'd be really grateful if someone could give me a hint why it's not working. Thank you in advance.

Related

How can I get webpack to emit its output to two locations?

My current configuration is as follows:
output: {
filename: 'bundle.js',
path: OUT_DIR
},
However I need bundles.js to go to two directories?
Can I accomplish this by simply passing an array of directories to path?
Or do I need to do something more complex?
Currently I have a bash script cpll which I have to type in manually after each build and it is tedious.
Hopefully web pack has a configuration option to send the output to two or more locations.
Research
google search
This SO question is 4 years old and does not have what I am lookin for - so
The documentation does not mention a way to do it here - webpack.
If there is not a configuration option how can I have it run a bash command automatically?
I tried passing it an array of strings instead of a string and it crashed with the obvious error:
Invalid configuration object. Webpack has been initialised using a
configuration object that does not match the API schema.
- configuration.output.path should be a string.
Passing an array will not work. Hmmm.
Trying another approach starting with a google - search
Brings up a possible solution - so
per request - complete exportFunc
const exportFunc = ( env ) => {
console.log('webpack.config.js-exportFunc', OUT_DIR);
return {
entry: `${IN_DIR}/index.jsx`,
output: {
filename: 'bundle.js',
path: '/Users/c/_top/ll-front/dist'
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.jsx?/,
include: IN_DIR,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: ['#babel/plugin-proposal-object-rest-spread', '#babel/plugin-proposal-class-properties'],
}
}
}
]
}
};
};
module.exports = exportFunc;
You can use webpack's multi-compiler mode by exporting an array of configs.
As in the docs:
Instead of exporting a single configuration object/function, you may export multiple configurations (multiple functions are supported since webpack 3.1.0). When running webpack, all configurations are built.
For example:
const config = {
// your webpack config
}
const outputPaths = ["path/one", "path/two"]
module.exports = outputPaths.map(outputPath => {
return {
...config,
name: outputPath,
output: {
...config.output,
path: path.resolve(__dirname, outputPath)
}
}
})
As you're using a function config you can do something like this:
const outputPaths = ["path/one", "path/two"]
module.exports = outputPaths.map(outputPath => {
return env => {
return {
entry: `${IN_DIR}/index.jsx`,
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, outputPath)
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.jsx?/,
include: IN_DIR,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: ['#babel/plugin-proposal-object-rest-spread', '#babel/plugin-proposal-class-properties'],
}
}
}
]
}
};
}
})
You could use multiple configurations instead. Here's the webpack documentation link.
To avoid code duplicaion consider your current config as an object. Then duplicate that object and override the output section of the duplicated object. Finally put both objects into an array. Use that array as your new config.
var yourCurrentConfig = {...};
var secondaryDestinationConfig = Object.assign(yourCurrentConfig, {
output: {
path: {
filename: 'bundle.js',
path: SECONDARY_DIR
}
}
});
var newConfig = [
yourCurrentConfig, secondaryDestinationConfig
];

Cannot export API in WebPack

I am creating a library in Javascript and I am shipping it as a bundle .js file using Webpack. The following file lib.js serves as the entry for Webpack in order to expose all the API in the library:
import * as bodies from "./bodies.js";
import * as composites from "./composites.js";
import * as connections from "./connections.js";
export var bodies = {
Body: bodies.Body,
Pyramid: composites.Pyramid
};
export var connections = {
Connection: connections.Connections
};
All the files imported basically export classes that I am referencing in lib.js:
// In bodies.js
export class Body { ... };
// In composites.js
export class Pyramid { ... };
// In connections.js
export class Connection { ... };
The file for bundling using Webpack is:
const path = require('path');
module.exports = {
entry: './lib.js',
output: {
filename: 'lib-bundle.js',
path: path.resolve(__dirname, 'out')
},
module: {
rules: [
/* In order to transpile ES6 */
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: { presets: ['env'] }
}
}
],
}
};
Webpack successfully bundle everything and I get my lib file in the end.
Problems using it
Then I use it in another project:
import * as mylib from "./lib/lib-bundle.js";
// Trying to use Pyramid
var pyramid = new mylib.bodies.Pyramid();
I use again Webpack to bundle this file into a file called start.js which i import in my page:
<script type="application/javascript" src="./start.js"></script>
However when running this page, I get an error. If I run the F12 tools and break in the bundle where I try creating an instance of the pyramid, there i can clearly see that object mylib does not have anything I have exposed. It is empty, lacking all the objects I exposed before.
What am I doing wrong?
You need to specify a libraryTarget in the output section of your webpack config file.
With it the bundle will correctly export your defined values, which
can be then imported with the various module loaders.
I suggest using libraryTarget: "umd" since it will add support for the most commonly used loaders. From the webpack docs:
This exposes your library under all the module definitions, allowing it to work with CommonJS, AMD and as global variable.
The resulting webpack config file is as follows:
const path = require('path');
module.exports = {
entry: './lib.js',
output: {
filename: 'lib-bundle.js',
path: path.resolve(__dirname, 'out'),
libraryTarget: 'umd',
},
module: {
rules: [
/* In order to transpile ES6 */
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: { presets: ['env'] }
}
}
],
}
};

Typescript: How to have some imports in the global scope?

Context:
I work on a project where the senior programmer decided to reduce the boilerplate code in newly created typescript files. Two examples of this boilerplate code would be importing the React library or the function that fetches and processes our localized strings.
Question:
Is it possible to have imports always available in files placed in certain folders without having to write the import tags every time?
What I've tried:
I've searched and read on the subject and found those links that talk about defining variables to use in the global space:
global.d.ts, global-modifying-module.d.ts, A typescript issue that seems to get it working
However, I was still unable to get it to work. Here is what I've tried:
At the root of the folder where I want React to be always available, I created a global.d.ts file which contains:
import * as R from "react";
declare global{
const React: typeof R;
}
With this file, the resource "React" is supposed to always be available to other files in subsequent folders. My IDE (Webstorm) recognizes that the import is there and allows me to manipulate the variable React without complaining. However, when I try to run the app, I get this error:
ReferenceError: React is not defined
I don't understand what is wrong with the code! Here is an example of the file I'm trying to render:
export default class World extends React.Component<{}, any> {
public render() {
return (<div>Hello world</div>);
}
}
From this stackoverflow question, I was under the impression that the problem could be webpack related. For the sake of completeness, here is the webpack config file we're currently using:
const webpack = require('webpack');
const path = require('path');
const BUILD_DIR = path.resolve(__dirname, './../bundles');
const WEBPACK_ENTRYFILE = path.resolve(__dirname, './../srcReact/ReactWrapper.tsx');
// `CheckerPlugin` is optional. Use it if you want async error reporting.
// We need this plugin to detect a `--watch` mode. It may be removed later
// after https://github.com/webpack/webpack/issues/3460 will be resolved.
const { CheckerPlugin } = require('awesome-typescript-loader');
const config = {
entry: [WEBPACK_ENTRYFILE],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.less']
},
output: {
path: BUILD_DIR,
filename: 'bundle.js'
},
plugins: [
new CheckerPlugin()
],
devtool: 'source-map', // Source maps support ('inline-source-map' also works)
module: {
loaders: [
{
loader: 'url-loader',
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.(ts|tsx)$/,
/\.css$/,
/\.less$/,
/\.ttf/,
/\.woff/,
/\.woff2/,
/\.json$/,
/\.svg$/
],
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
loader: 'url-loader',
test: /\.(ttf|woff|woff2)$/
},
{
loader: "style-loader!css-loader!less-loader",
test: /\.less$/
},
{
loader: "style-loader!css-loader",
test: /\.css$/
},
{
loader: "svg-loader",
test: /\.svg$/
},
{
loader: "json-loader",
test: /\.json$/
},
{
loader: "awesome-typescript-loader",
test: /\.(ts|tsx)$/
}
]
}
};
module.exports = config;
I am certain I am missing something. Can anyone help me?
Surely already open followed a tutorial like this
To do this creates a vendor file where you import these types of "global".
./src/vendors.ts;
import "react";
Add this file a to first place at entry parameter:
entry: { 'vendors': './src/vendors.ts', 'main': './src/main.ts' }
And add CommonChunkPlugins:
plugins: [ new CommonsChunkPlugin({
name: 'vendors'
}),
Like this in AngularClass with polyfills.

How can I include a multi part library with webpack?

I created a multi part library similar to the example from webpack/webpack/.../multi-part-library. In my apps I want to be able to import parts of my library like this:
ìmport Button from 'myLib/atoms/button';
// or
import { Button } from 'myLib/atoms';
My webpack configuration for the apps looks like this and I get an error (Cannot resolve module 'myLib/atoms' or Cannot resolve module 'myLib/atoms/button'):
module.exports = {
'entry': {
'app': './client.js',
},
'output': {
'filename': 'bundle.js',
},
'externals': {
'react': true,
'react-dom': true,
'myLib': true,
},
'module': {
'loaders': [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
},
]
},
};
The webpack configuration for the library looks like this:
const files = glob.sync('**/*.js', {
cwd: path.join(__dirname, 'atomic-design'),
absolute: true,
});
let entries = {};
files.forEach((file) => {
const name = path.basename(path.dirname(file));
const newName = `atoms/${name}`;
entries[newName] = file;
});
module.exports = {
'entry': entries,
'output': {
'path': path.join(__dirname, 'lib'),
'filename': 'myLib.[name].js',
'library': ['myLib', '[name]'],
'libraryTarget': 'umd',
'umdNamedDefine': 'myLib',
},
'externals': {
'react': true,
'react-dom': true,
},
'module': {
'loaders': [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel'
},
]
}
};
The files are structured like this:
- app
- client.js
- webpack.config.js
- myLib
- webpack.config.js
- atomic-design
- button
- index.js
- text-field
- index.js
So far I could only find tutorials for creating libraries with webpack, where they only use small examples of libraries.
Thanks for your help in advance!
Best regards,
JBrieske
I believe you need to add the paths (and adjust the from 'path' accordingly) for the modules you're trying to import to resolve.modulesDirectories.
Relevant documentation: https://webpack.github.io/docs/configuration.html#resolve-modulesdirectories.
Bear in mind that this will change in Webpack2, which is feature complete and is just short of documentation for a release.

using ES6 npm module (webpack) in the front end

I'm making an npm module using ES6 syntax (imports, exports etc) via webpack.
When I try to initialize an instance of the exported class in the frontend to test it, it isn't working and I've got a feeling it's to do with what CommonJS exports return vs ES6 exports.
example.js
export default class Example { ....
example-after-webpack-stuff.js
var Example = (function() ....
demo.js
var example = new Example();
demo.html
<script src="../example-after-webpack-stuff.js"></script>
<script src="demo.js"></script>
I receive the following:
Error: Uncaught TypeError: Example is not a function
EDIT
Webpack config:
module.exports = {
entry: './src/example.js',
output: {
filename: "./dist/example.js",
library: "Example",
libraryTarget: "var"
},
module: {
loaders: [
{
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['es2015']
}
}
]
}
};
Since babel 6, export default class Example will be compiled to exports.default = Example. While in Babel 5, it will be compiled to exports = Example. So you code will run without error using babel 5.
In babel 6, you can use CommonJS way module.exports:
class Example {
constructor() {
...
}
}
module.exports = Example;
Or you can use babel-plugin-add-module-exports to change babel 6's behavior.
npm install babel-plugin-add-module-exports --save-dev
Add it in webpack.config.js:
loaders: [
{
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['es2015'],
plugins: ['add-module-exports']
}
}
]

Categories