Allow global transforms with grunt browserify - javascript

I've added jQuery as a script tag in my html file and have added it to package.json for working with browserify-shim as follows:
"browserify": {
"transform": [
"browserify-shim"
]
},
"browserify-shim": {
"jquery": "global:jQuery"
},
I'm able to expose it in my main script file with a simple require('jquery') call.
The problem is that I'm using some jQuery plugins which internally do a require('jquery') and since browserify transforms don't apply to dependency of dependencies, it's causing browserify to complain with bundling since it cannot find jQuery.
Now I know that I can solve it by applying global-transforms by I cannot find a way to do it easily.
Browserify docs say that you cannot apply global-transforms in package file so the following don't work, (which I thought would):
"browserify": {
"global-transform": [
"browserify-shim"
]
},
"browserify": {
"transform": [
"browserify-shim"
],
"global": true
},
I also tried adding the option to my Gruntfile.js as follows, but even that doesn't work:
browserify: {
options: {
global: true
},
dist: {
files: {
'js/bundle.js': 'js/script.js'
}
},
},
The last option is to manually add a browserify-shim to every dependency's package.json, but I don't want to do it, since it means every time I add a new plugin, I would have to repeat the same process.
Any ideas to mitigate the above problem?

You should be able to apply global-transforms by providing transform with a hash option:
"browserify": {
"transform": [
["browserify-shim", {global: true}]
]
}

Related

Material-UI have different style result in production mode?

I am writing a React app that uses server-side rendering. I am following the instruction here to set up a file.
Here is my .babelrc configuration file
{
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": { "version": 3, "proposals": true },
"targets": {
"browsers": "> 1%, not ie 11, not op_mini all",
"node": 13
}
}
],
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-proposal-class-properties",
"#babel/plugin-transform-runtime",
[
"import",
{
"libraryName": "#material-ui/icons",
"libraryDirectory": "utils", // default: lib
"camel2DashComponentName": false // default: true
},
"#material-ui/icons"
]
]
}
And this is webpack.config.js file
const path = require("path");
const nodeExternals = require("webpack-node-externals");
const commonConfig = {
devtool: "source-map",
module: {
rules: [{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }]
},
resolve: {
alias: {
"#material-ui/core": "#material-ui/core/es"
}
}
};
module.exports = [
{
...commonConfig,
entry: "./src/client",
output: {
path: path.resolve(__dirname, "public")
}
},
{
...commonConfig,
target: "node",
entry: "./src/server",
output: {
path: path.resolve(__dirname, "server")
},
externals: [nodeExternals()]
}
];
(Here is the full code in CodeSandBox and here is in Github if you want to try out)
The problem appear is when I bundle up the file, in development mode, everything work just fine. But when I try production mode, the CSS part starts to behave weirdly. When the file is first loaded from localhost, it is styled correctly (this happens in a very short time), then the style goes wrong as some styling is missing.
When I try to investigate, I find that all the style that is missing is the part I wrote with makeStyles(). All the built-in styles work just fine.
I tried to remove all the resolve property in webpack.config.js following this post, but it doesn't work. No matter what I try to change that property, nothing happens.
So now the only way I found that can make the app work in production build is to remove the code that removes the styling file (you can find that part at the end of client.js file), but I'm not sure what is the result of doing so.
So my questions are:
What can you suggest the fix for the app?
Why there is such a difference between two modes, development and production? I get that the production mode will include some minification, tree shaking, etc., and the development has most of that except for minification. So why there is a difference?
Edit: I found two possible and workable fixes for this bug: one is to stop removing those CSS files (code that I wrote in client.js file); the other one is to remove the nodeExternal() plugin in webpack.config.js and bundle everything for the server file. What do you think ?
I had a similar issue, although without server-side rendering. It was caused by a different order of stylesheets in dev and prod environments, causing unwanted overwrites. In dev env all stylesheets created by makeStyles() were injected after ALL MUI stylesheets, but in production they were mixed.
Solution:
Add an option: { index: 1 } to all makeStyles() invocations, in order to place those sheets after the MUI sheets which have an index of 0 (by default). This optional argument is passed directly to underlying JSS's jss.createStyleSheet() and dictates the injection order:
const useStyles = makeStyles(
(...), // styles
{ index: 1 }, // optional argument for JSS, to set position after MUI stylesheets
)
(after: https://stackoverflow.com/a/62646041/624597)

External React component library JSX Babel wont compile

I'm trying to extract certain compoennts in my React Application to a separate reusable component library.
What I've done, is cloned this project: https://rinsejs.io/ and subsequently referenced the github repo in my main projects package.json
entry in package json of core project
"react-sharedlib": "git+ssh://git#github.com/myrepos/react-sharedlib.git#master",
Webpack.config inside react-sharedlib
// Path is in Node for free and will make simple resolving of directories no
// matter which part of your file system your library lives in
const path = require('path');
// Webpack is just a bunch of keys on module.exports!
module.exports = {
// This is where our app starts. This is why we hnpm install --save-dev babel-core#6.4.5ave done all this importing
// and exporting, to get to here
entry: './src/index.js',
// module (I know it's a bit weird to hanpm install --snpm install --save-dev babel-preset-es2015#6.3.13ave-dev babel-loader#6.2.1ve module.exports.module) is where we
// define all the rules for how webpack will deal with thing.
module: {
// rules takes an array, each item containing the respective rules
rules: [
{
// First up, our JavaScript rules.
// If you want to use the .jsx extension, you can change this line to
// test: /\.jsx?$/,
// The ? in the regex just means "optional"
test: /\.js$/,
// Don't bother spending time transpiling your installed packages
// exclude: /node_modules/,
// This is where we tell webpack to use babel to transpile our JS.
// The configuration can go here, but in this case it's in ./babelrc.js
use: {
loader: 'babel-loader',
},
},
{
// I haven't used SCSS in the base example, but it's here for you if you
// want! If you want to use CSS, you can change this next like's regex to
// /\.(css|scss)$/ or even just /\.css$/
test: /\.scss$/,
use: [
// These three libraries are commonly used together to turn Sass into
// CSS, then be able to load the CSS directly with imports. From there
// It gets put in the DOM for you.
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
},
{
// Some image formats so you can import images
test: /\.(png|gif|jpg|svg)$/,
use: {
loader: 'url-loader',
options: {
limit: 50000,
},
},
},
],
},
// Here we define explicitly the file types we intend to deal with
resolve: {
extensions: ['.scss', '.js', '.json', '.png', '.gif', '.jpg', '.svg'],
},
// This is where we define how everything gets output.
// dist is a common output folder, and it should be gitignored. The build can
// be run after publishing so you don't wind up with it in source control
output: {
path: path.resolve(__dirname, 'dist/'),
publicPath: '',
// You can do fun things here like use the [hash] keyword to generate unique
// filenames, but for this purpose rinse.js is fine. This file and path will
// be what you put in package.json's "main" field
filename: 'rinse.js',
// This field determines how things are importable when installed from other
// sources. UMD may not be correct now and there is an open issue to fix this,
// but until then, more reading can be found here:
// https://webpack.js.org/configuration/output/#output-librarytarget
libraryTarget: 'umd',
},
};
Babel config inside shared-lib:
{
"presets": ["#babel/env", "#babel/preset-react", "es2015", "react"],
"plugins": ["#babel/plugin-syntax-dynamic-import"]
}
Package.JSON inside shared-lib:
{
"name": "react-sharedlib",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"dependencies": {
"#babel/preset-react": "^7.0.0",
"babel-core": "^6.4.5",
"babel-loader": "^6.2.1",
"babel-preset-es2015": "^6.3.13"
},
"devDependencies": {
"#babel/plugin-syntax-dynamic-import": "^7.2.0",
"babel-preset-react": "^6.3.13"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/myrepos/react-sharedlib.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/myrepos/react-sharedlib/issues"
},
"homepage": "https://github.com/myrepos/react-sharedlib#readme"
}
When I try to build my project I get this error. (Which looks like a problem with babel in some capacity, not being able to reference the JSX syntax or needing a loader configured. Anyone any idea what I'm doing wrong here, or what other things to try? As you can see from my dependencies I've had a go at installing Babel loaders, but to no avail. I assume I may just be missing a piece of configuration somewhere to get it to recognise the HTML inside the JS file.
ERROR in /Users/moi/git/usersection/user-section/node_modules/react-sharedlib/src/components/Button/Button.js 23:8
Module parse failed: Unexpected token (23:8)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| // along without changing any of the contents. This is basically just creating
| // a copy to pass along
> return <ButtonWrapper {...props}>{props.children}</ButtonWrapper>;
| }
|
# /Users/moi/git/usersection/user-section/node_modules/react-sharedlib/src/components/Button/index.js 2:0-30 4:15-21
# /Users/moi/git/usersection/user-section/node_modules/react-sharedlib/src/index.js
# ./app/App.js
# ./index.js
Latest version of React btw.
Webpack 4.29.6
Update: **
Following on from the answer posted below, my shared library webpack.config.js file now contains this entry which unfortunately made no difference.
rules: [
{
// First up, our JavaScript rules.
// If you want to use the .jsx extension, you can change this line to
// test: /\.jsx?$/,
// The ? in the regex just means "optional"
test: /\.js$/,
// Don't bother spending time transpiling your installed packages
// exclude: /node_modules/,
// This is where we tell webpack to use babel to transpile our JS.
// The configuration can go here, but in this case it's in ./babelrc.js
use: {
loader: 'babel-loader',
options: {
babelrcRoots: [".", "node_modules/react-sharedlib"]
}
},
}
CORE PROJECT .babelrc:
{
"presets": ["#babel/env", "#babel/preset-react"],
"plugins": ["#babel/plugin-syntax-dynamic-import"]
}
SHARED PROJECT .babelrc:
{
"presets": ["#babel/env", "#babel/preset-react", "es2015", "react"],
"plugins": ["#babel/plugin-syntax-dynamic-import"]
}
By default, Babel assumes that .babelrc files in node_modules are ignored, because they were probably published on accident, and usually they reference plugins and presets that are in their devDependencies and thus probably aren't installed. The config could even be for a different version of Babel, so even if they were all installed, they still might not work.
This means you need to either:
Tell Babel explicitly that node_modules/react-sharedlib is safe to load the config for.
Configure your application's Babel config to compile that specific node_modules/react-sharedlib.
The first can be accomplished by specifying:
babelrcRoots: [".", "node_modules/react-sharedlib"],
in babel-loader's options.
The second would require using a babel.config.js config file in your application, and exporting your project-wide plugins there, so that they apply to any file you pass to Babel.
The Babel docs for config files are also a good place to review.

How to use multiple Jest presets with only one Jest configuration file/setup?

A project I'm working on is already configured with Jest and testing works as it should. This is how the current jest.config.js file looks like;
const ignores = [...];
const coverageIgnores = [...];
module.exports = {
roots: ['<rootDir>/src'],
globals: {
'ts-jest': {
tsConfig: 'tsconfig.json',
},
},
moduleFileExtensions: ['js', 'json', 'ts'],
testPathIgnorePatterns: [...ignores],
coveragePathIgnorePatterns: [...ignores, ...coverageIgnores],
testEnvironment: 'node',
coverageThreshold: {
global: {
branches: 86,
functions: 75,
lines: 86,
statements: 86,
},
},
preset: 'ts-jest',
};
The configuration currently uses the ts-jest preset. The project also involves a DynamoDB instance that should be tested and that's where multiple presets come into play. The current preset, ts-jest, should be used in combination with the #shelf/jest-dynamodb-preset (https://jestjs.io/docs/en/dynamodb). The problem is that the preset property in the config is of type String and doesn't support an array or an object.
I've read some similar questions like this one; Is it possible to use Jest with multiple presets at the same time?, but questions like these don't seem to have a definitive working solution on how to solve this problem.
Others suggest a solution in which a separate Jest config is created for every preset, but this is something I don't want and that probably will cause more problems in the future.
It would be ideal to have this single config file modified to allow multiple (here 2) presets, but how can this be achieved?
You can't actually use two presets but since the preset for shelf/jest-dynamodb is just setting other options in the jest setup, you can call them yourself. I was able to do this by just adding to my "jest" section of package.json:
"globalSetup": "./node_modules/#shelf/jest-dynamodb/setup.js",
"globalTeardown": "./node_modules/#shelf/jest-dynamodb/teardown.js",
This makes the same calls that the preset was doing, meaning you can leave the preset to ts-jest
This is specific to the marriage of ts-jest and jest-dynamodb, but what worked for me was to change the jest config like this:
"jest": {
"preset": "#shelf/jest-dynamodb",
"transform": {
"^.+\\.tsx?$": [
"ts-jest",
{}
]
},
// ...
}

How to change bower-installer path for one component

I am using bower-installer to copy files I need from bower_components folder into bower_dist folder. Here is relevant part of bower.json file:
"install": {
"path": "bower_dist"
},
"dependencies": {
"jquery": "~2.1.4",
"bootstrap": "~3.3.4",
"slick.js": "~1.5.5"
},
Now this is creating bower_dist folder and within it folder for each component. The problem is that within slick.js component I have few files (eot, svg, ttf, woff) that I need to have in /slick.js/fonts folder (rather than just /slick.js/ folder).
How do I do this? I've tried specifying special case for eot, svg, ttf and woff, but then that gets applied to all components. Plus I don't want to introduce need to specify all file types (js, css, etc)... rather want to just configure special font type for slick.js. Is this possible to do?
The problem here appears to be that slick.js uses a glob pattern in their bower.json main file array which is not supported...
Globs like js/*.js are not allowed.
You should do the following...
Override the required files for slick.js in your bower.json file (see Install multiple main files and Configurable paths)
"install": {
"base": "bower_dist",
"path": {
"js": "{name}",
"css": "{name}",
"eot": "{name}/fonts",
"svg": "{name}/fonts",
"ttf": "{name}/fonts",
"woff": "{name}/fonts"
},
"sources": {
"slick.js": [
"bower_components/slick.js/slick/slick.min.js",
"bower_components/slick.js/slick/slick.css",
"bower_components/slick.js/slick/slick-theme.css",
"bower_components/slick.js/slick/fonts/slick.eot",
"bower_components/slick.js/slick/fonts/slick.svg",
"bower_components/slick.js/slick/fonts/slick.ttf",
"bower_components/slick.js/slick/fonts/slick.woff"
]
}
}
Substitute bower_components for whatever your bower install directory is.
Follow this pull request.
This proved to be tougher than I thought:
"install": {
"path": "bower_dist",
"sources": {
"slick-carousel": {
"mapping": [
{ "bower_components/slick-carousel/slick/slick.min.js": "slick.min.js" },
{ "bower_components/slick-carousel/slick/slick.css": "slick.css" },
{ "bower_components/slick-carousel/slick/slick-theme.css": "slick-theme.css" },
{ "bower_components/slick-carousel/slick/ajax-loader.gif": "ajax-loader.gif" },
{ "bower_components/slick-carousel/slick/fonts/slick.eot": "fonts/slick.eot" },
{ "bower_components/slick-carousel/slick/fonts/slick.svg": "fonts/slick.svg" },
{ "bower_components/slick-carousel/slick/fonts/slick.ttf": "fonts/slick.ttf" },
{ "bower_components/slick-carousel/slick/fonts/slick.woff": "fonts/slick.woff" }
]
}
}
},
I've upgraded to new version of slick.js and now it's called slick-carousel in bower - just to explain difference in package name.

r.js, almond: Is it possible for two .js files containing almond to share dependencies?

Is it possible to use almond with a multipage setup as follows:
common.js is loaded on all pages & contains almond, bootstrap & jquery
main1.js is loaded only on page 1 & contains almond, and app/main1.js which requires jquery.
When i run the build for main1.js i am excluding bootstrap & jquery since it is in common.
on page1 common.js & main1.js are loaded but, i get an error: Uncaught Error: app/main1 missing jquery.
Is it possible to do this with almond or am I doing something wrong?
UPDATE:
I am useing django-require which converts python objects to command line entries for r.js, further more it renames the supplied modules to 'almond' and adds the named module to the include (this may be what is causing my error?). Also note, django-require does not permit include/exclude for REQUIRE_STANDALONE_MODULES, i added this functionality:
REQUIRE_STANDALONE_MODULES = {
"common": {
"out": "common.js",
"include": ["bootstrap", "jquery"],
"build_profile": "module.build.js"
},
"main1": {
"out": "main1.js",
"exclude": ["bootstrap", "jquery"],
"build_profile": "module.build.js"
}
}
Main1.js
require(['app/main1']);
This translates to a build file entry like this:
modules = {
"almond": {
"out": "common.js",
"include": ["common", "bootstrap", "jquery"],
"build_profile": "module.build.js"
},
"almond": {
"out": "main1.js",
"include:"main1",
"exclude": ["bootstrap", "jquery"],
"build_profile": "module.build.js"
}
}
It is possible. You just need to be clear about your inclusions and exclusions. In the following setup all the modules are stored in the js subdirectory and the output of optimization goes out to build. For the sake of simplicity jQuery is stored as js/jquery.js so there's no need to call require.config.
The files in js are: almond.js, jquery.js, main1.js and main2.js.
Here is the build configuration:
({
baseUrl: "js",
optimize: "none", // So that we can see what is going on in the bundles.
dir: "build",
removeCombined: true,
skipDirOptimize: true,
modules: [
{
name: "common",
create: true,
include: ["almond", "jquery"]
},
{
name: "main1",
exclude: ["jquery"],
insertRequire: ["main1"]
},
{
name: "main2",
exclude: ["jquery"],
insertRequire: ["main2"]
}
]
})
The create: true option for the common module is required so that the optimizer creates it. Presumably, a call to require.config would be put in js/common.js and then you'd remove this option.
The results of this optimization are loaded on page 1 with:
<script type="text/javascript" src="build/common.js"></script>
<script type="text/javascript" src="build/main1.js"></script>
Page 2 would load build/main2.js instead.
Loading Bootstrap requires a RequireJS configuration which is the same as the general case and is otherwise treated exactly like jQuery in the code above.

Categories

Resources