Scripts are loading multiple times and hell of a warnings in console - javascript

I am building a game in PIXI.JS using webpack as a module bundler. Honestly i had made the game without webpack and it's running perfectly but i have to install some npm packages for this project and for that i have added webpack to my project and copy paste all the code. but having issues.
The problem i am facing is that i have a some code in my app.js which is running multiple times. Although it's not in a loop and it's declared globally below is the code in my app.js
`// CREATING GAME DIV
const game = document.createElement("div");
// ADDING ID
game.id = "game-container";
// APPENDING TO BODY
document.body.appendChild(game);
export const app = new PIXI.Application({
width: window.innerHeight * (5 / 3),
height: window.innerHeight,
});
window.addEventListener("resize", () => {
app.view.width = window.innerHeight * (5 / 3);
app.view.height = window.innerHeight;
});
game.appendChild(app.view);`
The above code is pretty simple to understand but let me explain this code is making a div and appending it to body and then creating a PIXI.Application which is a canvas and appending it to div
The webpack bundle this code and when i run the production code check below pic
image showing how many divs get created
If you notice i have some h1 tags and they are only three because in my index.js i have below code
`import './style.css';
const fontBoogaloo = document.createElement('h1');
const fontBarlow = document.createElement('h1');
const fontLuckiestGuy = document.createElement('h1');
fontBarlow.textContent = 'WORDFALL';
fontBoogaloo.textContent = 'WORDFALL';
fontLuckiestGuy.textContent = 'WORDFALL';
fontBarlow.classList.add('font-barlow');
fontBoogaloo.classList.add('font-boogaloo');
fontLuckiestGuy.classList.add('font-luckiest-guy');
document.body.appendChild(fontBarlow)
document.body.appendChild(fontBoogaloo)
document.body.appendChild(fontLuckiestGuy);`
Self explanatory code, so this code is running only once but the code in app.js is running multiple times.
and there are hell of a warnings in console let me show you
hell of a warnings in console
i think this is related to pixi.js and nothing to do with webpack. i have tried uncomment all the code and use console.log('calling code') to check if the issue is in the code but no even a single console.log is being called 30 times.
The issue i think is in the webpack because as i said i have build this game with same code and it's running fine. here is my webpack.config.js in case you need it click here
I am not expert in webpack so please feel free to ask my for more info

Stop using live server extension
install webpack server plugin by npm install --save-dev webpack-dev-server
then add the following code in webpack.config.js
devServer: {
static: './dist',
},
optimization: {
runtimeChunk: 'single',
},
run webpack serve --open to start the server and everything will be good.

Related

vue application does not update when using webpack chunks

I have a mysterious behaviour here using webpack in a vue-application.
I have some view-paths stored in my database and I import the views in a for-loop dynamically like
for(let i = 0; i < routesList.length; i++) {
const viewPath = routesList[i];
const view = () => import('views/' + viewPath);
/* create a vue router object here */
}
This works absolutely fine but as soon as I am using WebpackChunkName all the future changes in my vue-files does not get compiled. The application seems to use some sort of cached files. Although npm watch recognizes the changes and recompiles correctly.
const view = () => import(/* webpackChunkName: "views" */ 'views/' + viewPath);
Another strange thing to notice is that the chunk gets named like
views0
views2
views4
etc.
The application runs on a Debian 8 distribution. These are the output-settings of my webpack.mix.js file
output: {
path: path.resolve(__dirname, 'demo'),
publicPath: '/demo/', // due to shared hosting
filename: `[name].${mix.inProduction() ? '[chunkhash].' : ''}js`,
chunkFilename: `[name].${mix.inProduction() ? '[chunkhash].' : ''}js`
}
Has anybody faced something similar? Really I am clueless about what is wrong... I even tried to delete the compiled chunks and mix-manifest.json in the output folder and recompiled it over and over again. But this does not change the situation.
Related
https://github.com/webpack/webpack/issues/2530
https://github.com/webpack/webpack-dev-server/issues/875
https://github.com/webpack/webpack-dev-server/issues/885
//Edit
9/27 - Regarding the related issues on github there could be a
problem with my paths in the webpack config file?
9/28 - Looks like this happens irregular. Updating my npm packages yesterday caused this to work for a moment. Today I'm stuck at the same again.

Resolving dynamic module with Webpack and Laravel Mix

Good time of the day,
Recently I've been trying to implement dynamic module loading functionality for my project. However, I'm failing for past few hours. To give you an idea of what I'm trying to achieve, here is the structure of the project
plugins
developer
assets
scss
developer.scss
js
developer.js
themes
theme_name
webpack.mix.js
node_modules/
source
js
application.js
bootstrap.js
scss
application.scss
_variables.scss
So, in order to get the available plugins, I've made the following function
/**
* Get all plugins for specified developer
* which have 'assets' folder
* #param developerPath
* #param plugins
*/
function getDeveloperPlugins(developerPath, plugins) {
if (fs.existsSync(developerPath)) {
fs.readdirSync(developerPath).forEach(entry => {
let pluginPath = path.resolve(developerPath, entry),
assetsPath = path.resolve(pluginPath, 'assets');
if (fs.existsSync(assetsPath))
plugins[entry] = assetsPath;
});
}
}
This function loads all the available plugins for the specified developer, then goes inside and looks for the assets folder, if it exists, then it returns it and we can work with the provided directory later.
The next step is to generate the reference for every plugin (direct path to the developer_name.js file) which later should be 'mixed' into one plugins.bundle.js file.
In order to achieve this, the following piece of code 'emerged'
_.forEach(plugins, (directory, plugin) => {
let jsFolder = path.resolve(directory, 'js'),
scssFolder = path.resolve(directory, 'scss');
if (fs.existsSync(jsFolder)) {
webpackModules.push(jsFolder);
let possibleFile = path.resolve(jsFolder, plugin + '.js');
if (fs.existsSync(possibleFile))
pluginsBundle.js[plugin] = possibleFile;
}
if (fs.existsSync(scssFolder)) {
webpackModules.push(scssFolder);
let possibleFile = path.resolve(scssFolder, plugin + '.scss');
if (fs.existsSync(possibleFile))
pluginsBundle.scss[plugin] = possibleFile;
}
});
And the last step before I'm starting to edit the configuration of the Webpack is to get the folders for both scss and js files for all plugins and all developers:
let jsPluginsBundle = _.values(pluginsBundle.js),
scssPluginsBundle = _.values(pluginsBundle.scss);
And here is where the problems start to appear. I've tried many solutions offered either here on GitHub (in respective repositories), but I've failed so many times.
The only error I'm having now is this one:
ERROR in F:/Web/Projects/TestProject/plugins/developer/testplugin/assets/js/testplugin.js
Module build failed: ReferenceError: Unknown plugin "transform-object-rest-spread" specified in "base" at 0, attempted to resolve relative to "F:\\Web\\Projects\\TestProject\\plugins\\developer\\testplugin\\assets\\js"
Yes, i know that webpack.mix.js file should be in the root folder of the project, however, i'm just developing theme, which uses modules developed by other members of the team.
So, idea was to:
Start build process: npm run dev|prod
Load plugins for all needed developers automatically
Use methods and html tags provided by the plugin (it is a mix of PHP for API routing and Vue.js for Components, etc) as follows: <test-component></test-component>
Any help is really appreciated, i just cant get my head around that error. If you need extra information, i'm ready to help since i myself need help to solve this issue =)
Update: The latest Webpack config used by mix.webpackConfig() (still failing though)
let webpackConfiguration = {
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: require.resolve('babel-loader'),
options: {
presets: [
'babel-preset-env'
].map(require.resolve),
plugins: [
'babel-plugin-transform-object-rest-spread'
].map(require.resolve)
}
}
}]
},
resolve: {
modules: webpackModules
}
};
mix.webpackConfig(webpackConfiguration);
And this is the content of the webpackModules variable:
[
'F:\\Web\\Projects\\TestProject\\themes\\testtheme\\node_modules',
'F:\\Web\\Projects\\TestProject\\themes\\testtheme',
'F:\\Web\\Projects\\TestProject\\plugins\\developer\\testplugin\\assets\\js',
'F:\\Web\\Projects\\TestProject\\plugins\\developer\\testplugin\\assets\\scss'
]
Okay, after 7 hours I've decided to try the most obvious method to solve the problem, to create node_modules folder in the root of the project and install laravel-mix there, and it worked like a charm.
Looks like, if it cant find the module in the directory outside the root scope of the Webpack, it will go up the tree to find the node_modules folder.
Developers should allow us to set the root folder for Webpack to fetch all the modules i guess, but well, problem is solved anyways.

Environment variable is undefined in electron even it has been set inside webpack.DefinePlugin

I have a requirement where we need to set dll path based upon whether it is executing in production or in development environment. So I decided to place that value in environment variable and tried to achieve that using webpack.DefinePlugin({}).
Method 1:
webpack.config.json
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV' : JSON.stringify('production')
})
And then I tried to get that value in electron's main process, In my case elec.js
elec.js
const Electron = require("electron");
const app = require("electron");
var dllPath = "";
function createWindow() {
let win = new BrowserWindow({
width: 800,
height: 600,
title: "Test",
icon: "Test.ico"
});
win.setMenu(null);
win.loadURL(
url.format({
pathname: path.join(__dirname, "../renderer/index.html"),
protocol: "file:",
slashes: true
})
);
if (process.env.NODE_ENV ==='production') {
dllPath = path.join(
__dirname,
"./../../dll/test.dll"
);
} else {
dllPath = path.join(
__dirname,
"./../../../dll/test.dll"
);
}
}
app.on("ready", createWindow);
But problem is that when I try to access that value in createWindow() function it is undefined so flow always goes to else block.
Is there anything I am missing?
Method 2:
I tried to achieve the same using cross-env node package, but no luck. Please find below code block which I tried using cross-env.
package.json
"scripts": {
"build": "cross-env process.env.NODE_ENV=production && rimraf ./dist/ && webpack --progress && node-sass
./src/renderer/scss/ -o ./dist/renderer/ && rimraf ./dist/renderer/includes/"
}
The problem is multi-faceted.
First, your elec.js is executed by Electron before the app is loaded. Electron runs elec.js, which creates the Browser window (let win = new BrowserWindow(...)) and loads HTML file (win.loadURL(...)) into it inside the browser process, the HTML then loads your webpack'ed js. So none of the webpacked js code is available in the elec.js. The webpack'ed code is also running in another process than the elec.js.
Another thing to note is that webpack plugin does not create any assignment to the variable it points too. It is done by simple text search and replace, in your example, all instances of process.env.NODE_ENV will be replaced with "production" string in the source code that is webpack'ed. That is not too obvious, but messes up the expected results.
One last thing - webpack plugin does not change any code in elec.js file, as that file is not webpack'ed.
So all that makes process.env.NODE_ENV from the build/webpack time not available in the elec.js code.
Once the mechanisms are clear, there are few ways to solve the problem, I will give general ideas, as there are plenty of discussions on each, and depending on circumstances and desired use case, some are better than others:
Generate a js file with necessary assignments based on environment variable during build (e.g. copy one of env-prod.js / env-dev.js -> env.js), copy it next to the elec.js, and reference it (require(env.js)) in elec.js.
Pass environment variable from command line (e.g. NODE_ENV=1 electron .) - it will get to elec.js.
Include a file into webpack based on environment variable (e.g. copy one of env-prod.js / env-dev.js -> env.js) and peek into webpacked' files from elec.js, e.g. using asar commands.
Use different version in package.json depending on build (e.g. version: "1.0.0-DEBUG" for debug), and read & parse it by calling app.getVersion() in elec.js. It is tricky as package.json should be a single file, but OS commands could be used (e.g. in "scripts") to copy one of prepared package.json files before invoking npm.
Here are some links that could help too:
Electron issue #7714 - discussion on relevant features in Electron
electron-is-dev - module checking if it is in dev
Electron boilerplate - example boilerplate that uses config/env-prod/dev files
The insight provided by iva2k is what allowed me to come to a solution for this same problem.
Using dotenv to create a .env file for my config got me halfway to where I wanted to be (setting up a few environment variables for use in a production setting). The problem then became that Electron wasn't passing those from the Main process down to the Renderer process by default.
The work-around is simple: use Electron's own ipcMain and ipcRenderer modules to pass the dotenv object between the two.
In your main file (e.g. your elec.js file), place an ipcMain event listener after requiring the module:
const config = require('dotenv').config();
const electron = require('electron');
const { app, BrowserWindow, ipcMain } = electron;
...
ipcMain.on('get-env', (event) => {
event.sender.send('get-env-reply', config);
});
Elsewhere, in your application's rendering-side, place this anywhere necessary:
async function getConfig()
{
const { ipcRenderer } = window.require('electron');
let config = null;
ipcRenderer.on('get-env-reply', (event, arg) => {
// The dotenv config object should return an object with
// another object inside caled "parsed". Change this if need be.
config = arg.parsed;
});
ipcRenderer.send('get-env');
return config;
}
This basically allowed me to declare one event in the Main process file, and then re-use it in any process-side file I wanted, thus allowing me to obfuscate config variables in a file that goes with the build, but isn't accessible to end-users without opening up the dev-tools.
Maybe late but can use simple hack in elec.js
const isProduction = process.env.NODE_ENV === 'production' || (!process || !process.env || !process.env.NODE_ENV);
In your console
For Windows
set MY_VARIABLE=true
For linux
$ export MY_VARIABLE=true
window.process.env.MY_VARIABLE

Getting started with unit testing JavaScript without a framework

I am building a JavaScript application (no framework yet, but I may move it to Backbone). I have created various classes, here's an example, chart.js:
var moment = require('moment');
var chart = {
...
getAllMonths: function(firstMonth, lastMonth) {
var startDate = moment(firstMonth);
var endDate = moment(lastMonth);
var monthRange = [];
while (startDate.isBefore(endDate)) {
monthRange.push(startDate.format("YYYY-MM-01"));
startDate.add(1, 'month');
}
return monthRange;
},
setMonths: function() {
// get data via ajax
this.globalOptions.months = this.getAllMonths(data['firstMonth'], data['lastMonth']);
}
};
module.exports = chart;
My file structure is as follows:
index.js
src/
chart.js
form.js
I import the two classes into index.js and use browserify to bundle these scripts up in order to use them in my web app.
Now I want to add tests for chart.js and form.js. I have added a new directory called test/ and empty test files:
index.js
src/
chart.js
form.js
test/
test_chart.js
test_form.js
My question now is what test_chart.js should look like in order to test the getAllMonths function, and what test runner I should use.
I've started experimenting with the following in test_chart.js:
console.log('hello world');
var chart = require('../src/chart');
var months = chart.getAllMonths('2014-02-01', '2015-03-01');
// assert if months.length != 14
But if I run this with node test/test_chart.js, I get errors about failed module imports for moment etc (shouldn't these be imported automatically with the original chart.js module?).
Secondly, what test runner could I use for this kind of simple testing? I'd like something that will automatically run everything in the test directory, and offers asserts etc.
I ended up using Mocha. It's really pretty easy:
npm install --save-dev mocha
mocha
Boom!
It automatically looks for files in the test/ folder.
Still having the problem with imports though.

How to add a broccoli plugin to ember-cli app with live-reload?

When I run ember build, the broccoli plugin runs correctly,
and outputs the sprite CSS file and sprite PNG file into the assets directory.
When I run ember serve, the same thing happens initially too.
However, when I save any file, causing Broccoli to rebuild its tree,
the sprite CSS and PNG files are no longer merged into the main app tree,
and when the page refreshes from live-reload the page no longer displays the sprited images.
Why does this happen?
How do I ensure that the outputs from my plugin get merged every time?
Details:
After asking this question,
and getting no responses despite putting a bounty on it,
I decided to write my own broccoli plugin for CSS image sprite generation:
broccoli-sprite
What I have tried so far:
#1
I am merging the output from my plugin with that of the main app using this in Brocfile.js
var app = new EmberApp(/* ... */);
/* other ember-cli init for app */
var broccoliSprite = require('broccoli-sprite');
var spritesTree = broccoliSprite(/* ... */);
var appTree = app.toTree();
var broccoliMergeTrees = require('broccoli-merge-trees');
module.exports = broccoliMergeTrees([spritesTree, appTree]);
I understand that this might not be the way to go, and I am fairly new to both ember-cli and broccoli, so pardon the newbie error, if this is one.
#2
In Brocfile.js, extend EmberApp to include a new tree for sprites:
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var broccoliSprite = require('broccoli-sprite');
EmberApp.prototype.sprites = function() {
console.log('EmberApp.prototype.sprites');
var spritesTree = broccoliSprite('public', this.options.sprite);
return spritesTree;
};
var originalEmberAppToArray = EmberApp.prototype.toArray;
EmberApp.prototype.toArray = function() {
var sourceTrees = originalEmberAppToArray.apply(this, arguments);
sourceTrees.push(this.sprites());
return sourceTrees;
};
The next release of Ember CLI will have first class support for add-ons. Thanks to Robert Jackson.
Take a look at https://github.com/rjackson/ember-cli-esnext to get an idea of how to package up broccoli-sprite for Ember CLI.
I look forward to using it in future apps :)

Categories

Resources