I use Webpack to create a library to use in all of my projects (both client and server).
This is my webpack.config.js:
const path = require('path');
const libraryName = 'shared';
const config = {
mode: 'development',
entry: {
utils: `${__dirname}/src/shared/utils.js`,
enums: `${__dirname}/src/shared/enums.js`
},
devtool: 'inline-source-map',
output: {
path: `${__dirname}/dist`,
filename: '[name].js',
library: libraryName,
libraryTarget: 'umd',
umdNamedDefine: true,
globalObject: 'typeof self !== "undefined" ? self : this'
},
externals: {
moment: {
commonjs: 'moment',
commonjs2: 'moment',
amd: 'moment',
root: 'moment'
}
},
module: {
rules: [{
test: /(\.jsx|\.js)$/,
loader: 'babel-loader',
exclude: /(node_modules|bower_components)/
}]
},
resolve: {
modules: [path.resolve('./node_modules'), path.resolve('./src')],
extensions: ['.json', '.js']
}
};
module.exports = config;
This is my enums.js:
import { EnvironmentMode} from './enums/config.enum';
export { EnvironmentMode };
This is my config.enum.js
const { enumUtils } = require('../utils/enum.utils');
// This enum defines the possible environment mode of the application.
const EnvironmentMode = enumUtils.createEnum(new Map([
['DEVELOPMENT', 'development'],
['TEST_LOCAL', 'test_local'],
['TEST_LOCAL_DEMO', 'test_local_demo'],
['TEST_DEMO', 'test_demo'],
['TEST_LINUX', 'test_linux'],
['PRODUCTION', 'production']
]));
module.exports = {
EnvironmentMode: EnvironmentMode
};
This is my utils.js:
import enumUtils from './utils/enum.utils';
export {
enumUtils
};
This is my enum.utils.js
class EnumUtils {
constructor() {}
// This method takes a map of elements and converts them to freeze objects (an enum-like object).
createEnum(mapItems) {
// Check the existence of the mapItems parameter. If not exists, return null instance.
if (!mapItems || mapItems.length <= 0) {
return null;
}
// This new object will hold the freeze array object.
const symbolMap = {};
// Assign each object.
mapItems.forEach((value, key) => {
symbolMap[key] = value;
});
// Freeze the object and return it.
return Object.freeze(symbolMap);
}
}
const enumUtils = new EnumUtils();
module.exports = enumUtils;
For some reason, when I build the project, and inject the compiled code to the projects, run any project, I get the following error:
C:\Or\Web\OSRStreamer\Streamer\streamer\src\shared\enums.js:212
var EnvironmentMode = enumUtils.createEnum(new Map([['DEVELOPMENT', 'development'], ['TEST_LOCAL', 'test_local'], ['TEST_LOCAL_DEMO', 'test_local_demo'], ['TEST_DEMO', 'test_demo'], ['TEST_LINUX', 'test_linux'], ['PRODUCTION', 'production']])); // This enum define the possible error code types that can appear when the server is listening and running.
^
TypeError: Cannot read property 'createEnum' of undefined
at Object../src/shared/enums/config.enum.js (C:\Or\Web\OSRStreamer\Streamer\streamer\src\shared\enums.js:212:33)
at __webpack_require__ (C:\Or\Web\OSRStreamer\Streamer\streamer\src\shared\enums.js:30:30)
at Object../src/shared/enums.js (C:\Or\Web\OSRStreamer\Streamer\streamer\src\shared\enums.js:191:15)
at __webpack_require__ (C:\Or\Web\OSRStreamer\Streamer\streamer\src\shared\enums.js:30:30)
at ./src/shared/enums.js.Object.defineProperty.value (C:\Or\Web\OSRStreamer\Streamer\streamer\src\shared\enums.js:94:18)
at C:\Or\Web\OSRStreamer\Streamer\streamer\src\shared\enums.js:97:10
at webpackUniversalModuleDefinition (C:\Or\Web\OSRStreamer\Streamer\streamer\src\shared\enums.js:3:20)
at Object.<anonymous> (C:\Or\Web\OSRStreamer\Streamer\streamer\src\shared\enums.js:10:3)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
What am I doing wrong?
My bad.
I did
const { enumUtils } = require('../utils/enum.utils');
Instead of
const enumUtils = require('../utils/enum.utils');
Fixed it. It works.
Related
I'm trying to create documentation for my component library, and I'm running into Uncaught ReferenceError: process is not defined when I try to get VuePress running in development. I'm not sure how to resolve this.
This library is scaffolded using vue-sfc-rollup
// enhanceApp.js
import ComponentLibrary from './../../src/entry.js'
export default ({ Vue, options, router, siteData }) => {
Vue.use(ComponentLibrary)
}
// entry.js
// Import vue components
import * as components from '#/lib-components/index';
// install function executed by Vue.use()
const install = function installVueCharge(Vue) {
if (install.installed) return;
install.installed = true;
Object.entries(components).forEach(([componentName, component]) => {
Vue.component(componentName, component);
});
};
// Create module definition for Vue.use()
const plugin = {
install,
};
// To auto-install on non-es builds, when vue is found
// eslint-disable-next-line no-redeclare
/* global window, global */
if ('false' === process.env.ES_BUILD) {
let GlobalVue = null;
if (typeof window !== 'undefined') {
GlobalVue = window.Vue;
} else if (typeof global !== 'undefined') {
GlobalVue = global.Vue;
}
if (GlobalVue) {
GlobalVue.use(plugin);
}
}
// Default export is library as a whole, registered via Vue.use()
export default plugin;
// To allow individual component use, export components
// each can be registered via Vue.component()
export * from '#/lib-components/index';
Edit: I've added my rollup.config.js as this is where process.env.ES_BUILD is defined.
// rollup.config.js
import fs from 'fs';
import path from 'path';
import vue from 'rollup-plugin-vue';
import alias from '#rollup/plugin-alias';
import commonjs from '#rollup/plugin-commonjs';
import replace from '#rollup/plugin-replace';
import babel from 'rollup-plugin-babel';
import { terser } from 'rollup-plugin-terser';
import minimist from 'minimist';
// Get browserslist config and remove ie from es build targets
const esbrowserslist = fs.readFileSync('./.browserslistrc')
.toString()
.split('\n')
.filter((entry) => entry && entry.substring(0, 2) !== 'ie');
const argv = minimist(process.argv.slice(2));
const projectRoot = path.resolve(__dirname, '..');
const baseConfig = {
input: 'src/entry.js',
plugins: {
preVue: [
alias({
resolve: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
entries: {
'#': path.resolve(projectRoot, 'src'),
},
}),
],
replace: {
'process.env.NODE_ENV': JSON.stringify('production'),
'process.env.ES_BUILD': JSON.stringify('false'),
},
vue: {
css: true,
template: {
isProduction: true,
},
},
babel: {
exclude: 'node_modules/**',
extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
},
},
};
// ESM/UMD/IIFE shared settings: externals
// Refer to https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
const external = [
// list external dependencies, exactly the way it is written in the import statement.
// eg. 'jquery'
'vue',
];
// UMD/IIFE shared settings: output.globals
// Refer to https://rollupjs.org/guide/en#output-globals for details
const globals = {
// Provide global variable names to replace your external imports
// eg. jquery: '$'
vue: 'Vue',
};
// Customize configs for individual targets
const buildFormats = [];
if (!argv.format || argv.format === 'es') {
const esConfig = {
...baseConfig,
external,
output: {
file: 'dist/vue-charge.esm.js',
format: 'esm',
exports: 'named',
},
plugins: [
replace({
...baseConfig.plugins.replace,
'process.env.ES_BUILD': JSON.stringify('true'),
}),
...baseConfig.plugins.preVue,
vue(baseConfig.plugins.vue),
babel({
...baseConfig.plugins.babel,
presets: [
[
'#babel/preset-env',
{
targets: esbrowserslist,
},
],
],
}),
commonjs(),
],
};
buildFormats.push(esConfig);
}
if (!argv.format || argv.format === 'cjs') {
const umdConfig = {
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-charge.ssr.js',
format: 'cjs',
name: 'VueCharge',
exports: 'named',
globals,
},
plugins: [
replace(baseConfig.plugins.replace),
...baseConfig.plugins.preVue,
vue({
...baseConfig.plugins.vue,
template: {
...baseConfig.plugins.vue.template,
optimizeSSR: true,
},
}),
babel(baseConfig.plugins.babel),
commonjs(),
],
};
buildFormats.push(umdConfig);
}
if (!argv.format || argv.format === 'iife') {
const unpkgConfig = {
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-charge.min.js',
format: 'iife',
name: 'VueCharge',
exports: 'named',
globals,
},
plugins: [
replace(baseConfig.plugins.replace),
...baseConfig.plugins.preVue,
vue(baseConfig.plugins.vue),
babel(baseConfig.plugins.babel),
commonjs(),
terser({
output: {
ecma: 5,
},
}),
],
};
buildFormats.push(unpkgConfig);
}
// Export config
export default buildFormats;
process.env is removed, you can use import.meta.env instead.
https://github.com/vitejs/vite/commit/8ad7ecd1029bdc0b47e55877db10ac630829c7e5
I've created node API webpack compiler in ES6. Without es6 everything works well. But if I use es6, I get this:
[13:29:41] TypeError: Cannot read property 'concat' of undefined
at new NormalModuleFactory (/private/var/www/MyProject/legacy/shop/node_modules/webpack/lib/NormalModuleFactory.js:115:51)
at Compiler.createNormalModuleFactory (/private/var/www/MyProject/legacy/shop/node_modules/webpack/lib/Compiler.js:586:31)
at Compiler.newCompilationParams (/private/var/www/MyProject/legacy/shop/node_modules/webpack/lib/Compiler.js:603:30)
at Compiler.compile (/private/var/www/MyProject/legacy/shop/node_modules/webpack/lib/Compiler.js:611:23)
at readRecords.err (/private/var/www/MyProject/legacy/shop/node_modules/webpack/lib/Compiler.js:284:11)
at Compiler.readRecords (/private/var/www/MyProject/legacy/shop/node_modules/webpack/lib/Compiler.js:479:11)
at hooks.run.callAsync.err (/private/var/www/MyProject/legacy/shop/node_modules/webpack/lib/Compiler.js:281:10)
at AsyncSeriesHook.eval [as callAsync] (eval at create (/private/var/www/MyProject/legacy/shop/node_modules/tapable/lib/HookCodeFactory.js:32:10), <anonymous>:6:1)
at AsyncSeriesHook.lazyCompileHook (/private/var/www/MyProject/legacy/shop/node_modules/tapable/lib/Hook.js:154:20)
at hooks.beforeRun.callAsync.err (/private/var/www/MyProject/legacy/shop/node_modules/webpack/lib/Compiler.js:278:19)
Process finished with exit code 1
This is my code:
import {Compiler} from 'webpack';
const config = require("./config/webpack.config");
class WebpackCompiler {
constructor(context) {
this.config = config;
this.compilerOptions = {};
this.compiler = new Compiler(context);
}
start() {
this.compiler.options = Object.assign({}, this.config, this.compilerOptions);
this.compiler.run().then((stats) => this._handleStats(stats)).catch((err) => this._handleErrors(err));
}
setOutput(output) {
this.compilerOptions.output = output;
}
setEntries(entires) {
this.compilerOptions.entry = entires;
}
_handleStats(stats) {
const statsErrors = stats.toJson();
if (stats.hasErrors()) {
console.error(statsErrors.errors.toString({
chunks: false,
colors: true
}));
}
if (stats.hasWarnings()) {
console.warn(statsErrors.warnings.toString({
chunks: false,
colors: true
}));
}
}
_handleErrors(err) {
if (err) {
console.error(err.stack || err);
if (err.details) {
console.error(err.details);
}
return;
}
}
}
export const CompilerFactory = {
create: function (context) {
return new WebpackCompiler(context);
}
}
After this, something like this:
var compiler = CompilerFactory.create(WEBPACK_CONTEXT);
compiler.setEntries({bundle: "./js/main.js"});
compiler.setOutput("./js/compiled");
compiler.start();
And simple webpack config:
const path = require('path');
const sourcePath = path.resolve("MY_PATH_TO_ROOT");
const mode = process.env.NODE_ENV === 'production' || "development";
module.exports = {
mode: mode,
node: {
__dirname: true
},
watchOptions: {
poll: true
},
devtool: "eval",
entry: {},
output: {
filename: '[name].js'
},
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
sourceMaps: true
}
}
]
}
]
},
externals: {
"jquery": "jQuery"
},
resolve: {
modules: [
path.resolve(sourcePath, 'node_modules')
]
}
};
Problem is after calling method Run(). In NormalModuleFactory.js, problem is in this row:
this.ruleSet = new RuleSet(options.defaultRules.concat(options.rules));
As I say, there is no much informations in the webpack documentation about using ES6. Do you everyone know, where is problem?
Thank you for your time.
I have a class defined in an index.js file like this
const BLOG = BLOG || {};
BLOG.ComponentFactory = class {
}
window.BLOG = BLOG;
Then, in a file init.js in a bundle, I try to access that var, the file is like this
const BLOG = BLOG || {};
BLOG.init = function() {
var c = new BLOG.ComponentFactory()
}
I get BLOG.ComponentFactory is not a constructor and I cannot understand why. Is the BLOG definition inside the file init.js masking the global var?
There is something strange: using Chrome debugger in the init function, I see Blog.ComponentFactory defined inside "Global", but if I add to the properties to watch, I see Blog.ComponentFactory = undefined
I'd like to understand what's happening.
I need to defin BLOG as a global var as I'm using ES6 together with old javascritpt code.
EDIT: if I use the following code all works (init.js)
const BLOG = BLOG || {};
BLOG.init = function() {
var c = new window.BLOG.ComponentFactory()
}
So, it seems the local const BLOG is masking the global BLOG var, but I need to define BLOG because otherwise I get BLOG is undefined. So, how do I solve the problem?
EDIT2: my webpack config (the problem is in the bundling, the vars are defined inside functions which are generated while bundling)
const webpack = require('webpack');
const path = require('path');
var config = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
]
},
// workaround for
// ERROR in ./node_modules/wpcom/build/lib/site.media.js
// Module not found: Error: Can't resolve 'fs' in '/node_modules/wpcom/build/lib'
node: {
fs: 'empty'
},
resolve: {
extensions: ['*', '.js', '.jsx']
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
};
var aConfig = Object.assign({}, config, {
name: "a",
entry: "./WebContent/js/blog/index.js",
output: {
path: __dirname + '/WebContent/js/blogW',
filename: "bundle.js",
publicPath: 'http://localhost:8080/js/blogW'
},
devServer: {
historyApiFallback: true,
contentBase: './WebContent',
publicPath: "http://localhost:8080/js/blogW",
hot: true
}
});
module.exports = [
aConfig
];
I am currently facing this issue for 3 days and unable to resolve:
Uncaught ReferenceError: require is not defined
at Object.<anonymous> (external "stream":1)
at n (bootstrap:19)
at Object.<anonymous> (react-dom-server.node.production.min.js:10)
at n (bootstrap:19)
at Object.<anonymous> (server.node.js:4)
at n (bootstrap:19)
at Object.<anonymous> (server.js:3)
at n (bootstrap:19)
at Object.<anonymous> (renderer.js:2)
at n (bootstrap:19)
Basically, in my file renderer.js, I have this functionality:
import {renderToString} from 'react-dom/server';
export default (req) => {
let context = {};
const content = renderToString(
<Router location={req.path} context={context}>
<FullPage />
</Router>
);
};
This is the main line which is causing the error basically, this happens when I try to import the renderToString method from 'react-dom/server':
I have tried out different things like removing target: 'node' but none of the solutions worked. What possible might be causing this? I have been stuck on this for the last 3 days and not sure what it is.
My Webpack configuration is:
webpack.base.config.js
module.exports = {
devtool: 'source-map',
module: {
rules: [
{
test: /\.js?$/,
options: {
presets: [
'react', 'stage-2',
['env', { targets: { browsers: ['last 2 versions'] } }]
]
},
loader: 'babel-loader',
exclude: /node_modules/
}
]
}
};
webpack.server.js
const webpack = require('webpack');
const path = require('path');
const SERVER_DIR = path.resolve(__dirname, 'src/server');
const BUILD_DIR = path.resolve(__dirname, 'dist');
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base.config');
const config = {
target: 'node',
entry: SERVER_DIR + '/index.js',
mode: 'production',
output: {
path: BUILD_DIR,
filename: 'bundle.server.js'
}
};
module.exports = merge(baseConfig, config);
I am trying to upgrade an old framework I built in javascript to es6/module standards and I have a lot of troubles.
One of my current problems is that due to server side rendering my modules are sometime loaded in the node environment and are trying to access the window, causing errors.
Is there a principled way to manage this ?
The main jQuery file has a nice failback if window is undefined and can load in node without a fuss. I am trying to implement this in web-pack by I am stumbling.
This is my current webpack config
// #flow
// import path from 'path'
import webpack from 'webpack'
const WDS_PORT = 7000
const PROD = JSON.parse(process.env.PROD_ENV || '0')
const libraryName = 'experiment'
const outputFile = `${libraryName}${PROD ? '.min' : '.max'}.js`
const plugins = [
new webpack.optimize.OccurrenceOrderPlugin(),
]
const prodPlugins = plugins.concat(new webpack.optimize.UglifyJsPlugin())
// not really working
export default {
entry: './builder.js',
target: 'web',
output: {
path: `${__dirname}/lib`,
filename: outputFile,
library: libraryName,
libraryTarget: 'umd',
umdNamedDefine: true,
},
module: {
loaders: [
{
test: /(\.jsx|\.js)$/,
loader: 'babel-loader',
exclude: /(node_modules|bower_components)/,
},
],
},
devtool: PROD ? false : 'source-map',
resolve: {
extensions: ['.js', '.jsx'],
},
externals: {
chartjs: {
commonjs: 'chartjs',
amd: 'chartjs',
root: 'Chart', // indicates global variable
},
lodash: {
commonjs: 'lodash',
amd: 'lodash',
root: '_', // indicates global variable
},
jquery: 'jQuery',
mathjs: {
commonjs: 'mathjs',
amd: 'mathjs',
root: 'math', // indicates global variable
},
'experiment-boxes': {
commonjs: 'experiment-boxes',
amd: 'experiment-boxes',
root: 'experimentBoxes', // indicates global variable
},
'experiment-babylon-js': {
commonjs: 'experiment-babylon-js',
amd: 'experiment-babylon-js',
root: 'EBJS', // indicates global variable
},
},
devServer: {
port: WDS_PORT,
hot: true,
},
plugins: PROD ? prodPlugins : plugins,
}
And this is my main entry point builder.js
/* --- Import the framwork --- */
import TaskObject from './src/framework/TaskObject'
import StateManager from './src/framework/StateManager'
import State from './src/framework/State'
import EventData from './src/framework/EventData'
import DataManager from './src/framework/DataManager'
import RessourceManager from './src/framework/RessourceManager'
import {
Array,
String,
diag,
rowSum,
getRow,
matrix,
samplePermutation,
rep,
Deferred,
recurse,
jitter,
delay,
looksLikeAPromise,
mustHaveConstructor,
mustBeDefined,
mandatory,
debuglog,
debugWarn,
debugError,
noop,
} from './src/framework/utilities'
/* add it to the global space in case user want to import in a script tag */
if (typeof window !== 'undefined') {
window.TaskObject = TaskObject
window.StateManager = StateManager
window.State = State
window.EventData = EventData
window.DataManager = DataManager
window.RessourceManager = RessourceManager
window.jitter = jitter
window.delay = delay
window.Deferred = Deferred
}
export {
TaskObject,
StateManager,
State,
EventData,
DataManager,
RessourceManager,
Array,
String,
diag,
rowSum,
getRow,
matrix,
samplePermutation,
rep,
Deferred,
recurse,
jitter,
delay,
looksLikeAPromise,
mustHaveConstructor,
mustBeDefined,
mandatory,
debuglog,
debugWarn,
debugError,
noop,
}
Am I on the right track?
Ok my solution so far, although feels like a hack, protects against require() in node environment.
In the ENTRY FILE of your webpack config check for window being defined.
Here is an example when trying to re-bundle babylonjs which relies heavily on window and would generate an error when required by node:
builder.js
let BABYLON = {}
let OIMO = {}
if (typeof window !== 'undefined') {
BABYLON = require('./src/babylon.2.5.full.max')
OIMO = require('./src/Oimo').OIMO
window.BABYLON = BABYLON
window.OIMO = OIMO
}
module.exports = { BABYLON, OIMO }
webpack.config.babel.js
import path from 'path'
import webpack from 'webpack'
const WDS_PORT = 7000
const PROD = JSON.parse(process.env.PROD_ENV || '0')
const plugins = [
new webpack.optimize.OccurrenceOrderPlugin(),
]
const prodPlugins = plugins.concat(new webpack.optimize.UglifyJsPlugin())
export default {
entry: [
'./builder.js',
],
output: {
filename: PROD ? 'babylon.min.js' : 'babylon.max.js',
path: path.resolve(__dirname, 'lib/'),
publicPath: `http://localhost:${WDS_PORT}/lib/`,
library: 'EBJS',
libraryTarget: 'umd',
umdNamedDefine: true,
},
module: {
rules: [
{ test: /\.(js|jsx)$/, use: 'babel-loader', exclude: /node_modules/ },
],
},
devtool: PROD ? false : 'source-map',
resolve: {
extensions: ['.js', '.jsx'],
},
devServer: {
port: WDS_PORT,
hot: true,
},
plugins: PROD ? prodPlugins : plugins,
}
Testing the bundle in node with a simple file like so:
bundle.test.js
const test = require('./lib/babylon.min.js')
console.log(test)
Will produce in the terminal:
$ node bundle.test.js
{ BABYLON: {}, OIMO: {} }