Webpack and modernizr causes TypeError: document is undefined error - modernizr

I am using webpack to bundle up my javascript files.
My Webpack config (which is passed to webpack using gulp) looks like this:
var webpackConfig = {
context: __dirname,
entry: {
"app": "./js/app.js"
},
output: {
path: path.join(__dirname, ".."),
filename: "/js/[name].js",
chunkFilename: "/js/[id].js"
},
plugins: [
new webpack.ResolverPlugin(
new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
)
],
resolve: {
modulesDirectories: ['js', 'bower_components', 'node_modules']
}
};
My app.js is a simple require:
require('modernizr/modernizr.js');
Webpack builds the file without any problems and the generated file contains modernizr.
The problem is that when I include the file on a page and test it, modernizr errors out:
TypeError: document is undefined
docElement = document.documentElement,
The bundled file from webpack looks like this:
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
__webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
/*!
* Modernizr v2.8.3
* www.modernizr.com
*
* Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
* Available under the BSD and MIT licenses: www.modernizr.com/license/
*/
/*
* Modernizr tests which native CSS3 and HTML5 features are available in
* the current UA and makes the results available to you in two ways:
* as properties on a global Modernizr object, and as classes on the
* <html> element. This information allows you to progressively enhance
* your pages with a granular level of control over the experience.
*
* Modernizr has an optional (not included) conditional resource loader
* called Modernizr.load(), based on Yepnope.js (yepnopejs.com).
* To get a build that includes Modernizr.load(), as well as choosing
* which tests to include, go to www.modernizr.com/download/
*
* Authors Faruk Ates, Paul Irish, Alex Sexton
* Contributors Ryan Seddon, Ben Alman
*/
window.Modernizr = (function( window, document, undefined ) {
var version = '2.8.3',
Modernizr = {},
/*>>cssclasses*/
// option for enabling the HTML classes to be added
enableClasses = true,
/*>>cssclasses*/
docElement = document.documentElement,
/** rest of modernizr code here **/
return Modernizr;
})(this, this.document);
/***/ }
/******/ ])
What's causing this problem?

On Webpack 2, I think I got it working by using {test: /modernizr/, loader: 'imports-loader?this=>window!exports-loader?window.Modernizr'}, in my module.rules.
See this Webpack bug filed here: https://github.com/webpack/webpack/issues/512#issuecomment-288143187

This issue is caused by Modernizr passing this.document to the closure it creates. Unfortunately, webpack wraps all that in yet another closure of its own, causing this.document to return null.
The problem can be resolved by setting this using the imports loader when requiring:
require('imports?this=>window!modernizr/modernizr.js');

I had the same issue, but was not requiring Modernizr directly. I required a library that had Modernizr packaged in it. The earlier solution does not work in that scenario. I eventually ended up using the script-loader:
require('script!package/vendor-bundle.js);

In Webpack config file added this :
module: {
...
loaders: [
...
{ test: /[\\\/]modernizr dependecie path[\\\/]modernizr\.js$/,
loader: "imports?this=>window!exports?window.Modernizr" }
...
]
}
for that you'll need to install the imports-loader and exports-loader .

Related

how to run vue app in the same domain with laravel sanctum for SPA

I need help in running my Vue spa in the same domain as my laravel app , when running "npm run serve" in terminal I think it's working but when I go to the browser it's refusing connection. I haven't done the backend which I will use sanctum for handling API. Has anybody here have the same project working on like me? love to make conversations to solve this.
Thanks in advance
here is the vue.config.js file
const path = require('path')
const webpack = require('webpack')
const createThemeColorReplacerPlugin = require('./config/plugin.config')
function resolve (dir) {
return path.join(__dirname, dir)
}
/**
* check production or preview(pro.loacg.com only)
* #returns {boolean}
*/
function isProd () {
return process.env.NODE_ENV === 'production'
}
const assetsCDN = {
css: [],
// https://unpkg.com/browse/vue#2.6.10/
js: [
'//cdn.jsdelivr.net/npm/vue#2.6.10/dist/vue.min.js',
'//cdn.jsdelivr.net/npm/vue-router#3.1.3/dist/vue-router.min.js',
'//cdn.jsdelivr.net/npm/vuex#3.1.1/dist/vuex.min.js',
'//cdn.jsdelivr.net/npm/axios#0.19.0/dist/axios.min.js'
]
}
// webpack build externals
const prodExternals = {
vue: 'Vue',
'vue-router': 'VueRouter',
vuex: 'Vuex',
axios: 'axios'
}
// vue.config.js
const vueConfig = {
configureWebpack: {
// webpack plugins
plugins: [
// Ignore all locale files of moment.js
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
],
// if prod is on, add externals
externals: isProd() ? prodExternals : {}
},
chainWebpack: (config) => {
config.resolve.alias
.set('#$', resolve('src'))
const svgRule = config.module.rule('svg')
svgRule.uses.clear()
svgRule
.oneOf('inline')
.resourceQuery(/inline/)
.use('vue-svg-icon-loader')
.loader('vue-svg-icon-loader')
.end()
.end()
.oneOf('external')
.use('file-loader')
.loader('file-loader')
.options({
name: 'assets/[name].[hash:8].[ext]'
})
// if prod is on
// assets require on cdn
if (isProd()) {
config.plugin('html').tap(args => {
args[0].cdn = assetsCDN
return args
})
}
},
css: {
loaderOptions: {
less: {
modifyVars: {
// less vars,customize ant design theme
'primary-color': '#00B4E4',
// 'link-color': '#F5222D',
'border-radius-base': '4px'
},
javascriptEnabled: true
}
}
},
}
if (process.env.VUE_APP_PREVIEW === 'true') {
vueConfig.configureWebpack.plugins.push(createThemeColorReplacerPlugin())
}
module.exports = vueConfig
module.exports = {
devServer: {
host: 'app.paymate-ui.test'
}
}
If I understand you correctly, you want to use Laravel and Vue.js together in the same application folder?
Should be pretty easy then.
First off, build your application with Vue scaffolding for the frontend.
Then, make a route that redirects everything to a single controller method that returns a spa view. (Or use a closure)
In this view, include your app.js as an asset and include the main Vue component (something like <app></app>).
Then build your Vue app. All requests will now be forwarded to the spa view, which includes your app.js, which should bootstrap Vue.

Laravel Mix BrowserSync It is not triggered

According to the Laravel Mix documents. I'm using Webpack to compile styles and launch BrowserSync in the process.
This is my complete webpack.mix.js document. You can see browserSync on line 92:
require('laravel-mix-merge-manifest');
const fs = require('fs');
const mix = require('laravel-mix');
const pathEnv = 'resources/sass/_enviroments/' + process.env.NODE_ENV;
const sites = [
'RP-ES',
'TZ-ES',
'CAL-ES',
'RUP-ES',
'FL-ES',
'SP-ES',
'WPX-IT',
'WPX-UK',
'WPX-CH',
'WPX-FR',
'WPX-DE',
'WPX-PT',
'WPX-NL',
'MTN-ES',
'MTN-DE',
'MTN-FR'
];
const tmpFiles = [];
try
{
if (process.env.NODE_ENV == 'development')
{
if (!process.env.hasOwnProperty('npm_config_only_css'))
generateJS();
if (!process.env.hasOwnProperty('npm_config_only_js'))
{
if (!process.env.hasOwnProperty('npm_config_site'))
{
// throw('In development, parameter "--site" is mandatory, one of the follow values: "'+sites.join('", "')+'"');
sites.forEach(slug=>{
generateSiteCss(slug)
});
}
else
generateSiteCss(process.env.npm_config_site);
}
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
mix.webpackConfig({plugins: [new BundleAnalyzerPlugin()]});
}
else
{
generateJS();
sites.forEach(slug=>{
generateSiteCss(slug)
});
}
mix.version()
mix.mergeManifest()
mix.then(deleteTmpFiles);
}
catch(e)
{
deleteTmpFiles();
throw e;
}
function generateJS()
{
console.log('Generating JS...');
// app scripts (common in all pages)
mix.js('resources/js/app.js', 'public/js')
.extract()
// individual scripts (auto register) to use alone en certain pages
.js('resources/js/components/helpcenter_results.vue.js', 'public/js/vue_components') // used in helpcenter
.js('resources/js/components/newsletter.vue.js', 'public/js/vue_components') // used in home
.js('resources/js/components/slick_carousel.vue.js', 'public/js/vue_components') // used in product pages & designs list
.js('resources/js/components/vue_tab.vue.js', 'public/js/vue_components') // used in login
// combined components with auto register included
.js('resources/js/products_page.js', 'public/js')
.js('resources/js/checkout.js', 'public/js')
.js('resources/js/payment_methods.js', 'public/js')
.js('resources/js/cart.js', 'public/js')
.js('resources/js/products_list.js', 'public/js')
.js('resources/js/accounts.js', 'public/js')
// required libs that are used in certain pages and are not available througth npm
.copyDirectory('resources/js/libs','public/js/libs')
.copyDirectory('resources/fonts','public/fonts')
.copyDirectory('resources/css','public/css')
.browserSync('regalospersonales.local');
}
function generateSiteCss(slug)
{
console.log('Generating CSS for the site: '+ slug +'...');
let pathSite = `resources/sass/_sites/${slug}`;
let outputPath = `public/css/sites/${slug}`;
let tmpPath = `resources/sass/${slug}`;
let includePaths = [
pathEnv,
pathSite
];
fs.writeFileSync(`${tmpPath}_common.scss`, `#import '_common';`);
fs.writeFileSync(`${tmpPath}_helpcenter.scss`, `#import '_helpcenter';`);
tmpFiles.push(`${tmpPath}_common.scss`);
tmpFiles.push(`${tmpPath}_helpcenter.scss`);
mix.sass(`${tmpPath}_common.scss`, `${outputPath}/common.css`, { includePaths: includePaths })
.sass(`${tmpPath}_helpcenter.scss`, `${outputPath}/helpcenter.css`, { includePaths: includePaths })
//.then(deleteTmpFiles)
//console.log(result);
//throw new Exception('asdfasdf');
}
function deleteTmpFiles(){
console.log('Deleting temporal files...');
tmpFiles.forEach(f=>{
if (fs.existsSync(f))
fs.unlinkSync(f);
});
}
And of course I have sync browser installed with my package.json:
"devDependencies": {
"browser-sync": "^2.26.7",
"browser-sync-webpack-plugin": "^2.0.1",
Everything looks good. But when I execute:
npm run watch
All my styles and javascript are compiled, watch is activated but it doesn't say anything about BrowserSync.
No error or anything happens, it's like BrowserSync is ignored.
What's going on?

How to run two separate mocha test files from a single testrunner.html? [duplicate]

I am new to mocha. My scripts below works when i run from the terminal. However, there is no result when i run from testrunner.html. On checking, it seems to be because of var xl = require('./excel');. if i comment this statement, it works. How can i make this work? i need to import custom modules for my script.
Updated test.js to incorporate RequireJS
Post changes: works on browser and termial
module1.js
if(typeof define !== 'undefined')
{
define([], function() {
return {
get: function() {
return get();
}
};
});
}
else if(typeof exports !== 'undefined') {
module.exports = {
get: function(){
return get();
}
};
}
function get(){
return "hello node world";
}
test.js
if(typeof requirejs == 'undefined') {var requirejs = require('requirejs');}
if(typeof chai == 'undefined') {var chai = require('chai');}
requirejs.config({
baseUrl: '.',
paths: {
},
nodeRequire: require
});
describe("RequireTest()", function(){
var module1;
before(function(done){
requirejs(['./module1'],
function(_module) {
console.log('before fired');
module1 = _module;
if(typeof requirejs == 'undefined') {mocha.run();}
done();
});
});
it('test case: ', function(){
console.log(module1.get());
chai.expect(1+1).to.equal(2);
});
});
testrunner.html (snippet)
<div id="mocha"></div>
<script src="../node_modules/mocha/mocha.js"></script>
<script src="../node_modules/chai/chai.js"></script>
<script src="../node_modules/requirejs/require.js"></script>
<script>mocha.setup('bdd')</script>
<script src="./test.js"></script>
<script>mocha.run();</script>
When you run Mocha at the command line you are using Node.js, which provides require.
When you run it in the browser, there is no require that the browser provides. You need to use a module loader at run-time like RequireJS or SystemJS. Or you need to use a packager like Webpack or Browserify that will process your code beforehand and turn it into a single bundle that incorporates all your code.
Note that whether third-party modules you use can be loaded in a browser, is a determination you have to make module-by-module. If you use a module that uses Node's child_process module to spawn a new process, for instance, you won't be able to just use that module in the browser because browsers don't provide child_process.

Require statement error on importing modules from TestRunner.html

I am new to mocha. My scripts below works when i run from the terminal. However, there is no result when i run from testrunner.html. On checking, it seems to be because of var xl = require('./excel');. if i comment this statement, it works. How can i make this work? i need to import custom modules for my script.
Updated test.js to incorporate RequireJS
Post changes: works on browser and termial
module1.js
if(typeof define !== 'undefined')
{
define([], function() {
return {
get: function() {
return get();
}
};
});
}
else if(typeof exports !== 'undefined') {
module.exports = {
get: function(){
return get();
}
};
}
function get(){
return "hello node world";
}
test.js
if(typeof requirejs == 'undefined') {var requirejs = require('requirejs');}
if(typeof chai == 'undefined') {var chai = require('chai');}
requirejs.config({
baseUrl: '.',
paths: {
},
nodeRequire: require
});
describe("RequireTest()", function(){
var module1;
before(function(done){
requirejs(['./module1'],
function(_module) {
console.log('before fired');
module1 = _module;
if(typeof requirejs == 'undefined') {mocha.run();}
done();
});
});
it('test case: ', function(){
console.log(module1.get());
chai.expect(1+1).to.equal(2);
});
});
testrunner.html (snippet)
<div id="mocha"></div>
<script src="../node_modules/mocha/mocha.js"></script>
<script src="../node_modules/chai/chai.js"></script>
<script src="../node_modules/requirejs/require.js"></script>
<script>mocha.setup('bdd')</script>
<script src="./test.js"></script>
<script>mocha.run();</script>
When you run Mocha at the command line you are using Node.js, which provides require.
When you run it in the browser, there is no require that the browser provides. You need to use a module loader at run-time like RequireJS or SystemJS. Or you need to use a packager like Webpack or Browserify that will process your code beforehand and turn it into a single bundle that incorporates all your code.
Note that whether third-party modules you use can be loaded in a browser, is a determination you have to make module-by-module. If you use a module that uses Node's child_process module to spawn a new process, for instance, you won't be able to just use that module in the browser because browsers don't provide child_process.

Require a jQuery-Plugin with Webpack

I want to use Webpack in order to create one single scripts.js file out of all needed Javascript files.
Within my main.js I require three modules:
require('jquery');
require('readmore');
require('foundation');
My webpack.config.js is this:
var path = require('path');
module.exports = {
entry: ["./js/main.js"],
output: {
path: path.resolve(__dirname, 'build'),
filename: "scripts.js"
},
resolve: {
modulesDirectories: ["bower_components", "node_modules"],
alias: {
jquery: '../bower_components/jquery/dist/jquery.js',
readmore: '../node_modules/readmore-js/readmore.js',
foundation: '../bower_components/foundation-sites/dist/js/foundation.js'
}
}
}
My problem: as readmore-js is a jQuery-Plugin it requires jQuery by itself.
I got this error after running Webpack:
ERROR in ./~/readmore-js/readmore.js
Module not found: Error: Can't resolve 'jquery' in '/Users/myName/www/myProject/node_modules/readmore-js'
# ./~/readmore-js/readmore.js 17:4-31
# ./js/main.js
# multi main
From my understanding the problem is that readmore also wants to load the module jQuery within the directory "nodes_modules". My first approach was to resolve this problem by adding moduleDirectories to the config-file, but it does still not work.
And even in this case, the plugin shouldn't load jQuery again.
Do you have any idea how I can load jQuery globally and then "tell" all modules which require jQuery by themself "look, it's there!"
As it may helps, the following is copied out of the plugin's readmore.js:
(function(factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}
You can use webpack.ProvidePlugin for this:
Remove require jquery from main.js:
require('readmore');
require('foundation');
Configure webpack.ProvidePlugin inside webpack.config.js:
var path = require('path');
module.exports = {
entry: ["./js/main.js"],
output: {
path: path.resolve(__dirname, 'build'),
filename: "scripts.js"
},
resolve: {
modulesDirectories: ["bower_components", "node_modules"],
alias: {
readmore: '../node_modules/readmore-js/readmore.js',
foundation: '../bower_components/foundation-sites/dist/js/foundation.js'
}
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
]
}

Resources