How to exclude Express view engines from Webpack bundle - javascript

I'm bundling my CLI app using Webpack v4. One of the dependencies is Express, and this causes a warning:
WARNING in ./node_modules/express/lib/view.js 81:13-25
Critical dependency: the request of a dependency is an expression
# ./node_modules/express/lib/application.js
# ./node_modules/express/lib/express.js
# ./node_modules/express/index.js
That comes from this line within Express:
/**
* Initialize a new `View` with the given `name`.
*
* Options:
*
* - `defaultEngine` the default template engine name
* - `engines` template engine require() cache
* - `root` root path for view lookup
*
* #param {string} name
* #param {object} options
* #public
*/
function View(name, options) {
var opts = options || {};
this.defaultEngine = opts.defaultEngine;
this.ext = extname(name);
// ...
if (!opts.engines[this.ext]) {
// load engine
var mod = this.ext.substr(1)
debug('require "%s"', mod)
// default engine export
var fn = require(mod).__express // <-- this require is the problem
There's quite a few questions asking about how to fix this by not bundling express at all, or not bundling anything from node_modules.
For me that would defeat the point (I'm trying to shrink my deployed file footprint), so I want to fix this whilst keeping express inside my bundle. In my case I don't use view engines at all, and this require exists solely to load view engines on demand, so I really just want the warning to go away.
If I'm confident that this require will never be called, how can I tell webpack to ignore it completely?

What you could maybe try is alter you webpack config module rules so that
view unit uses the null-loader
This will of course make View return null but if you never touch views it might be ok.
example.
rules: [
{
test: require.resolve("express/view"),
use: 'null-loader',
},
],
Looking at application
this.set('view', View); hopefully View been null here doesn't cause issues.
The only other place View is then mentioned in application is then in render that you say your not using. So fingers crossed this won't cause any side effects.

Related

How to use node modules outside of webpack encore files?

I have started using webpack encore in my Symfony 5 web app and still haven't figured it all out.
I'd like to use node modules outside of webpack encore files but I can't find a way of doing this.
For example I have installed Datatables and I'd like to use it in a JavaScript file inside the public/assets/js directory, but when I try I get $(...).DataTable is not a function.
In my app.js I do import all the modules I need :
import 'select2';
import 'parsleyjs';
import 'datatables';
Here is my webpack.config.js :
const Encore = require('#symfony/webpack-encore');
// Manually configure the runtime environment if not already configured yet by the "encore" command.
// It's useful when you use tools that rely on webpack.config.js file.
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
Encore
// directory where compiled assets will be stored
.setOutputPath('public/build/')
// public path used by the web server to access the output path
.setPublicPath('/build')
// only needed for CDN's or sub-directory deploy
//.setManifestKeyPrefix('build/')
/*
* ENTRY CONFIG
*
* Each entry will result in one JavaScript file (e.g. app.js)
* and one CSS file (e.g. app.css) if your JavaScript imports CSS.
*/
.addEntry('app', './assets/app.js')
// enables the Symfony UX Stimulus bridge (used in assets/bootstrap.js)
.enableStimulusBridge('./assets/controllers.json')
// When enabled, Webpack "splits" your files into smaller pieces for greater optimization.
.splitEntryChunks()
// will require an extra script tag for runtime.js
// but, you probably want this, unless you're building a single-page app
// .enableSingleRuntimeChunk()
.disableSingleRuntimeChunk()
/*
* FEATURE CONFIG
*
* Enable & configure other features below. For a full
* list of features, see:
* https://symfony.com/doc/current/frontend.html#adding-more-features
*/
.cleanupOutputBeforeBuild()
.enableBuildNotifications()
.enableSourceMaps(!Encore.isProduction())
// enables hashed filenames (e.g. app.abc123.css)
.enableVersioning(Encore.isProduction())
.configureBabel((config) => {
config.plugins.push('#babel/plugin-proposal-class-properties');
})
// enables #babel/preset-env polyfills
.configureBabelPresetEnv((config) => {
config.useBuiltIns = 'usage';
config.corejs = 3;
})
// enables Sass/SCSS support
//.enableSassLoader()
// uncomment if you use TypeScript
//.enableTypeScriptLoader()
// uncomment if you use React
//.enableReactPreset()
// uncomment to get integrity="..." attributes on your script & link tags
// requires WebpackEncoreBundle 1.4 or higher
//.enableIntegrityHashes(Encore.isProduction())
// uncomment if you're having problems with a jQuery plugin
.autoProvidejQuery()
;
module.exports = Encore.getWebpackConfig();

How does webpack-encore works with symfony 5?

I'm getting a bit mad dealing with webpack-encore in a symfony 5 project.
There is few things i just don't understand. first of all here is my webpack.config.js :
const Encore = require('#symfony/webpack-encore');
// Manually configure the runtime environment if not already configured yet by the "encore"
command.
// It's useful when you use tools that rely on webpack.config.js file.
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
Encore
// directory where compiled assets will be stored
.setOutputPath('public/build/')
// public path used by the web server to access the output path
.setPublicPath('/build')
// only needed for CDN's or sub-directory deploy
//.setManifestKeyPrefix('build/')
/*
* ENTRY CONFIG
*
* Each entry will result in one JavaScript file (e.g. app.js)
* and one CSS file (e.g. app.css) if your JavaScript imports CSS.
*/
.addEntry('app', './assets/app.js')
// enables the Symfony UX Stimulus bridge (used in assets/bootstrap.js)
.enableStimulusBridge('./assets/controllers.json')
// When enabled, Webpack "splits" your files into smaller pieces for greater optimization.
.splitEntryChunks()
// will require an extra script tag for runtime.js
// but, you probably want this, unless you're building a single-page app
.enableSingleRuntimeChunk()
/*
* FEATURE CONFIG
*
* Enable & configure other features below. For a full
* list of features, see:
* https://symfony.com/doc/current/frontend.html#adding-more-features
*/
.cleanupOutputBeforeBuild()
.enableBuildNotifications()
.enableSourceMaps(!Encore.isProduction())
// enables hashed filenames (e.g. app.abc123.css)
.enableVersioning(Encore.isProduction())
.configureBabel((config) => {
config.plugins.push('#babel/plugin-proposal-class-properties');
})
// enables #babel/preset-env polyfills
.configureBabelPresetEnv((config) => {
config.useBuiltIns = 'usage';
config.corejs = 3;
})
// enables Sass/SCSS support
//.enableSassLoader()
// uncomment if you use TypeScript
//.enableTypeScriptLoader()
// uncomment if you use React
//.enableReactPreset()
// uncomment to get integrity="..." attributes on your script & link tags
// requires WebpackEncoreBundle 1.4 or higher
//.enableIntegrityHashes(Encore.isProduction())
// uncomment if you're having problems with a jQuery plugin
//.autoProvidejQuery();
module.exports = Encore.getWebpackConfig();
The thing is when i use {{ asset('build/images/my-image.png') }} in my template the file is not found though it is in assets/images/my-image.png
How should i access my image???
Why it is not in manifest.json ??
Why am i not having images in my public/build/ folder ?
What path should i be using to reference my image in app.css as a background-image for example ?
This thing is a nightmare to use & configure.....
Thanks in advance
Thank you guys you are both right,
.copyFiles({
from: './assets/images',
// optional target path, relative to the output dir
to: 'images/[path][name].[ext]',
// if versioning is enabled, add the file hash too
//to: 'images/[path][name].[hash:8].[ext]',
// only copy files matching this pattern
//pattern: /\.(png|jpg|jpeg)$/
})
this part was missing in my config files, then i did not run the build command.....
But it still not an easy tool.
Have a good day.
you tryed run command for build files npm run build ?
or run command for recompile automatically assets
how of documentation exemple
https://symfony.com/doc/current/frontend/encore/simple-example.html

How to handle blocked scripts in requirejs

I am using require js to load google analytics.
In config I have
requirejs.config({
"paths": {
"ga": "//www.google-analytics.com/analytics",
...
And I have a module that depends on ga that initialises analytics.
Everything works fine until someone uses a browser plugin that blocks google analytics.
When that happens, the resulting javascript error breaks everything.
failed to load resource : blocked by clien
uncaught error: script error for: ga
How can I tell requirejs not to have a fit if a certain module fails to load?
How can you make a module optional?
Thanks.
require takes a 3rd argument which is an error callback, so you can assign window.ga to a function which always returns undefined. This avoids errors when calling google analytics functions elsewhere in your code.
require(['ga'], function(data) {
window.ga('create', 'UA-XXXXXXXX-X');
window.ga('send', 'pageview');
}, function() {
window.ga = function(){};
});
You could require the module within your own module code but outside of the module definiton requirements, but this does mean you can't quite as easily chain on dependencies you need. i.e.
define([ /* Normal dependencies here ... */], function() {
try {
require(['ga']);
} catch (error) {
// Handle lack of GA if needed
}
};
Alternatively you'd have to write your own module wrapper which synchronously blocks as it attempts the above, then returns GA if it was successful, or null otherwise.
I found the best way is to use the array notation for path definitions. This way you can define the external URL for the module, and a local fallback, in your requirejs path configuration. No need for additional try/catch blocks or module-specific error handling.
Documentation link:
http://requirejs.org/docs/api.html#pathsfallbacks
I defined a module named noop which defines an empty function, and then set up my paths like this:
requirejs.config({
"paths": {
"ga": [
"//www.google-analytics.com/analytics",
"util/noop"
],
...
The best solution, It works for me.
Open lib/mage/requirejs/resolver.js file.
/**
* Checks if provided module has unresolved dependencies.
*
* #param {Object} module - Module to be checked.
* #returns {Boolean}
*/
function isPending(module) {
return !!module.depCount;
}
Replace with this bellow code:
/**
* Checks if provided module is rejected during load.
*
* #param {Object} module - Module to be checked.
* #return {Boolean}
*/
function isRejected(module) {
return registry[module.id] && (registry[module.id].inited || registry[module.id].error);
}
/**
* Checks if provided module has unresolved dependencies.
*
* #param {Object} module - Module to be checked.
* #returns {Boolean}
*/
function isPending(module) {
if (!module.depCount) {
return false;
}
return module.depCount > _.filter(module.depMaps, isRejected).length;
}
Thanks

Change sails.js EJS views to use .html extensions instead of .ejs extensions?

Is it possible to configure sails.js apps to use .html extentions rather than .ejs (but still use the ejs view engine)?
sails new app creates ./views/home/index.ejs and ./views/layout.ejs.
I'd like to change the extensions to .html but keep everything else working the same way.
ie: I would now have ./views/home/index.html and ./views/layout.html, and the home page would still be injected into the layout page, as per normal.
How can I configure this please?
In your config/views.js:
engine: {
ext: 'html',
fn: require('ejs').renderFile
},
Seems though that the future support for this feature is not guaranteed, since they removed this from docs, so use with caution.
Another approach
Sails provides EJS templating by default.To override this and to use .html files , here is a simple solution. In your Sails App , go to config/routes.js. You will see following code there
module.exports.routes = {
/***************************************************************************
* *
* Make the view located at `views/homepage.ejs` (or `views/homepage.jade`, *
* etc. depending on your default view engine) your home page. *
* *
* (Alternatively, remove this and add an `index.html` file in your *
* `assets` directory) *
* *
***************************************************************************/
'/': {
view: 'homepage'
}
/***************************************************************************
* *
* Custom routes here... *
* *
* If a request to a URL doesn't match any of the custom routes above, it *
* is matched against Sails route blueprints. See `config/blueprints.js` *
* for configuration options and examples. *
* *
***************************************************************************/
};
Remove the route to '/' as shown below . Keep it blank
New routes.js will look like
module.exports.routes = {
//Remove '/' :)
};
Okay !!! now it’s done you can use your HTML files in Sails app . Put your index.html in assets folder . Sails will now load views from here :)
In latest sails.js 0.11, this also valid:
engine: 'ejs',
extension: 'html',
To check how they do this, in /node_modules/sails/lib/hooks/views/configure.js:
if (typeof sails.config.views.engine === 'string') {
var viewExt = sails.config.views.extension || sails.config.views.engine;
sails.config.views.engine = {
name: sails.config.views.engine,
ext: viewExt
};
}

node.js global configuration

I'm currently working on a small console project that depends a lot on the arguments that are passed initially and I'm looking for a good way to handle a configuration object in nodejs.
I have the project currently fully working with the following example but I think I'm relaying on the caching of modules when using 'require'.
lets assume a module options.js
'use strict';
var options = {
configName: '.jstail',
colorActive: (process.platform === 'win32') ? false : true, // deactivate color by default on windows platform
quiet: false,
debug: false,
config: null,
logFile: null,
setting: null
};
module.exports = options;
And my initial module init.js
#!/usr/bin/env node
'use strict';
var options = require('options'); // require above options module
// modify the options object based on args
I then have a logger that depends on this options
For example if quiet is set to true no logging should happen
logger.js
'use strict';
var options = require('options');
/**
* prints to console if not explicitly suppresed
* #param {String} text
*/
function log(text) {
if (!options.quiet) {
console.log('[LOG]: ' + text);
}
}
My big problem is (I think) that I'm relaying on the caching of nodejs modules when I require the options module in the logger
So my two questions are:
Am I right that this only works because of the caching of the modules that nodejs does for me?
Is there any better way to handle a dynamic global configuration?
I know there are several questions and tutorials around with a config file but thats not what I'm looking for.
Yes, this only works because of caching, though I wouldn't call it caching (but node.js docs do) rather than lazy initialization. It's ok to rely on that, a lot of modules do some initialization of first require, using it for configuration is also typical. Generally speaking, require is a node.js way of accessing global singleton objects.
The other way to do it is to load configuration from a single file, modify it and then pass it to other modules who need it, like this:
//index.js
var config = require('./config')
config.flag = false
var module1 = require('./module1')(config)
//module1.js
module.exports = function (config) {
// do stuff
}
It makes code more decoupled and testable but adds complexity. Difference between these two approaches is basically the same as using globals vs dependency injection. Use whatever you like.

Categories