MultipleMatchesException while using react webjar - reactjs

I was using react with play-framework from webjar. While running the code MultipleMatchesException exception is thrown. After looking into the issue, I find react.production.min.js file in two locations. One in cjs and other in umd.
build.sbt line: "org.webjars" % "react" % "16.3.2"
What is the difference between cjs and umd? Why are both being downloaded and how to specify only one to use???
Thanks in advance

CJS = Common JS
UMD = Universal Module Definition
You need to be more specific in your webjars-locator usage, so something like:
#webJarsUtil.locate("umd/react.production.min.js").script()

Related

Codemirror - Module parse failed: Unexpected token

I am using react-codemirror2. I used npx create-react-app appname to create my app.
But when I try to run the development server it gives me the following error -
./node_modules/codemirror/mode/rpm/changes/index.html 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
> <!doctype html>
|
| <title>CodeMirror: RPM changes mode</title>
One solution suggested to change the modulesDirectories. I tried doing so using npm run eject. But wasn't successful at doing it.
Please help me with the same
Go to solutions section if you are in a hurry.
The why
The reason for this error is the way bundling dynamic imports works in webpack. Imports go by providing a starting part of a path and you may refine that through an end part that holds a path that precise an extension.
Ex:
import(`codemirror/mode/${snippetMode}/${snippetMode}`)
ref: https://webpack.js.org/api/module-methods/#dynamic-expressions-in-import
Such an import is processed by webpack through the following regex ^\.\/.*$. That we can see in the error message:
| <title>CodeMirror: RPM changes mode</title>
# ./node_modules/codemirror/mode/ sync ^\.\/.*$ ./rpm/changes/index.html
And that's basically to determine the possible modules. And bundle them as chunks for code splitting.
Because of that open matching regex. So all files of all types (extensions) are matched. Then depending on the extension. The correct loader would be used. If we had the html-loader setup and configured through a rule. That wouldn't fail. As the loader will handle that module (webpack module [html]). Even though that can be an option to handle the problem. It wouldn't be the right thing to do. As it would create an extra bundle for the module. And also some entries for it. In the main bundle.
Dynamic Imports types and there resolution
All types get code splitted (chunks created for them for code splitting). Except for the last one.
Absolute full path. (static) ==> Imported dynamically and code splitted.Ex:
import('codemirror/mode/xml/xml')
The exact path and module will be resolved and a chunk for it will be created.
Dynamic path with a starting path.
Ex:
import(`codemirror/mode/${snippetMode}/${snippetMode}`)
All paths with this regex codemirror\/mode\/.*$ are matched.
Dynamic path with a starting path and an ending path with extension as well.ex:
import(`./locale/${language}.json`)
All paths with the following regex would be matched ./locale/.*\.json which limit it to .json extension module only.
Full variable import.Ex:
import(someVar)
Doesn't create code splitting at all. Neither tries to match. Because it can match just quite anything in the project. Even if the variable is set to a path someVar = 'some/static/path'. It wouldn't check and resolve the variable association.
The solutions
No electron or electron.
module.noParse
module: {
noParse: /codemirror\/.*\.html$/,
rules: [
// ...
noParse tell webpack to not parse the matched files. So it both allows us to exclude files and boost the performance. It works all great. And can be one of the best solutions as well. You can use a regex. Or a function.
ref: https://webpack.js.org/configuration/module/#module-noparse
Don't use the import('some/path' + dynamicEl) format and use instead
const dynamicPath = 'some/path' + dynamicEl
import(dynamicPath) // That would work just ok
Use magic comments [wepackExclude or wepackInclude] with import (if electron and using require => convert require to import + magic comment). Magic comments don't work with require but only import.
ex:
import(
/* webpackExclude: /\.html$/ */
`codemirror/mode/${snippetMode}/${snippetMode}`
)
or even better
import(
/* webpackInclude: /(\.js|\.jsx)$/ */
`codemirror/mode/${snippetMode}/${snippetMode}`
)
Include allows us to make sure we are targeting exactly what we want to target. Excluding HTML. May still create chunks for some other files that are not .js. It's all relative to what we want. If you want to include only a specific extension. An include is better. Otherwise, if we don't know. And some other extension would be required. Then an exclude is better.
ref: https://webpack.js.org/api/module-methods/#magic-comments
Magic comments examples and usage:
// Single target
import(
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
/* webpackExports: ["default", "named"] */
'module'
);
// Multiple possible targets
import(
/* webpackInclude: /\.json$/ */
/* webpackExclude: /\.noimport\.json$/ */
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
/* webpackPrefetch: true */
/* webpackPreload: true */
`./locale/${language}`
);
And to fully ignore code splitting
import(/* webpackIgnore: true */ 'ignored-module.js');
If nodejs or electron and the import should be processed as commonjs require. Use the externals config property like in the example bellow:
externals: {
'codemirror': 'commonjs codemirror'
}
which works like this. Webpack for any import with codemirror (left part). convert it to the commonjs import without bundling it (right part).
import(`codemirror/mode/${snippetMode}/${snippetMode}`)
will be converted to:
require(`codemirror/mode/${snippetMode}/${snippetMode}`)
instead of bundled.
extenals doc ref: https://webpack.js.org/configuration/externals/#externals
If electron. And the feature should not be bundled. use window.require for all nodejs electron API calls (Otherwise set it on entry file window.require = require). And use it instead.
Its electron, nodejs ==> Webpack stay the hell out of this
The doctype declaration is incorrect, it should have been:
<!DOCTYPE html>
Notice DOCTYPE should be in caps.

Importing self-created libraries in reactjs

I'm using React and ES6 using babel and webpack. I am very new to this ecosystem.
I am trying to import some common utility functions into my jsx file but react is unable to find the file
homepage.jsx
var pathToRoot = './../..';
import path from 'path';
import React from 'react';
import ReactDOM from 'react-dom';
var nextWrappedIndex = require(path.join(pathToRoot,'/lib/utils.js')).nextWrappedIndex;
//some react/JSX code
utils.js
var nextWrappedIndex = function(dataArray) {
//some plain js code
return newIndex;
}
exports.nextWrappedIndex = nextWrappedIndex;
Directory structure is as follows:
src
|--app.js
|--components
| |--homepage
| |--homepage.jsx
|
|--lib
| |--utils.js
I am on a windows 10 machine and was facing issues during compilation providing the path by any other means. Using path.join solved compilation issue but the browser while rendering throws this error
Uncaught Error: Cannot find module '../../lib/utils.js'.
How do I accomplish this?
Also, is this the best way to do it(if altogether it is way it is supposed to be done in such ecosystem)?
One of the best and easiest way I have found in such a setup is to use Webpack aliases.
Webpack aliases will simply associate an absolute path to a name that you can use to import the aliased module from anywhere. No need to count "../" anymore.
How to create an alias?
Let's imagine that your Webpack config is in the parent folder of your src folder.
You would add the following resolve section in your config.
const SRC_FOLDER = path.join(__dirname, 'src')
resolve: {
alias: {
'my-utils': path.join(SRC_FOLDER, 'lib', 'utils')
}
}
Now, anywhere in your app, in any of your modules or React component you can do the following:
import utils from 'my-utils'
class MyComponent extends React.component {
render () {
utils.doSomething()
}
}
Small note about this method. If you run unit tests with a tool like enzyme and you don't run the component tested through Webpack, you will need to use the babel-plugin-webpack-alias.
More info on Webpack website: Webpack aliases
I solved this by replacing
var nextWrappedIndex = require(path.join(pathToRoot,'/lib/utils.js')).nextWrappedIndex;
with
import nextWrappedIndex from './../../lib/utils.js';
I tried to reproduce your code and Webpack printed me the following error:
WARNING in ./app/components/homepage/homepage.jsx
Critical dependencies:
50:0-45 the request of a dependency is an expression
# ./app/components/homepage/homepage.jsx 50:0-45
It means that Webpack couldn't recognize your require() expression because it works only with static paths. So, it discourages the way you are doing.
If you would like to avoid long relative paths in your import, I'd recommend you to set up Webpack.
First, you can set up aliases per Amida's answer.
Also, you can set up an extra module root via resolve.modules to make webpack look into your src folder, when you are importing something absolute, like lib/utils.js

Import Highcharts and highcharts-more (AngularJS 1.5 + TypeScript + webpack)

I'm trying to use Highcharts with some of its extensions (like "highcharts-more") in a project that uses webpack, TypeScript and AngularJS (version 1.5).
I've installed Highcharts through npm (https://www.npmjs.com/package/highcharts), but I'm not able to import the extensions that come with it.
The actual trick I'm doing is to set some global variables in the webpack config file
plugins: [
new webpack.ProvidePlugin({
Highcharts: 'highcharts',
HighchartsMore: 'highcharts/highcharts-more',
HighchartsExporting: 'highcharts/modules/exporting'
})
]
and extending Highcharts manually
HighchartsMore(Highcharts);
HighchartsExporting(Highcharts);
without any import in between. With this non-ideal solution TypeScript is complaining because
error TS2304: Cannot find name 'HighchartsMore'
error TS2304: Cannot find name 'HighchartsExporting'
In particular with Highcharts there is no error. Which I guess has to do with the fact that Highcharts is the only thing I manage to import, via
import * as Highcharts from 'highcharts';
which I can substitute with the Highchart global declaration in the webpack config. What I would like is to import every module in a clean way, something like
import {HighchartsMore} from 'highcharts-more';
Any idea is very much appreciated.
This type of error can occur when you do not have definition files for exported variables. Those Highcharts extensions still require them - you might want to read more about importing modules without d.ts here: https://github.com/Urigo/meteor-static-templates/issues/9 - it might change in the future.
You need to create a d.ts file for the extensions. For highcharts-more this is my file:
/// <reference path="index.d.ts" />
declare var HighchartsMore: (H: HighchartsStatic) => HighchartsStatic;
declare module "highcharts/highcharts-more" {
export = HighchartsMore;
}
reference path points to standard DefinietelyTyped Highcharts file from here https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/highcharts/highcharts.d.ts
It allows to use type from Highcharts.d.ts because initializing will need proper typing for initializing extension:
HighchartsMore(Highcharts);
And finally don't forget to include all d.ts files by defining tsconfig or writing reference path in your files.
remove these lines from webpack.config.js:
plugins: [
new webpack.ProvidePlugin({
Highcharts: 'highcharts',
HighchartsMore: 'highcharts/highcharts-more',
HighchartsExporting: 'highcharts/modules/exporting'
})
]
install typings file for highcharts using this:
npm install --save #types/highcharts
change your import statements to following:
import * as Highcharts from 'highcharts';
import HighchartsMore = require('highcharts/highcharts-more');
HighchartsMore(Highcharts);

TS2307 error when including external modules to Typescript file

I installed a module via npm, and am trying to access it inside my typescript file.
npm install marker-animate-unobtrusive --save
import SlidingMarker = require('marker-animate-unobtrusive');
This results in
//Error TS2307: Cannot find module 'marker-animate-unobtrusive'
Search for this issue brings upchanging the compiler options, others mention creating a d.ts file for Type Script to recognize the module, but I never got a clear answer anywhere. I tried these methods, but with little success so far.
I am using Angular 2 and Ionic 2 for this, if that information helps.
Any help is appreciated!!
The problem is because the SlidingMarker npm module doesn't yet have a type definition.
1) Create generic definition in typings/marker-animate-unobtrusive.d.ts:
declare module 'marker-animate-unobtrusive' {
const x: any;
export = x;
}
2) Add this file to list of definitions in typings/main.d.ts (or typings/index.d.ts if you are using the newer typings):
/// <reference path="marker-animate-unobtrusive.d.ts"></reference>
3) Next, update your import statement:
import * as SlidingMarker from 'marker-animate-unobtrusive';
Volia! Note, you may need to change any variables cast as "SlidingMarker" to "any" to avoid other TypeScript errors.

XQuery 3.0 and maps in Saxon

I would like to experiment with map features in Saxon (http://www.saxonica.com/documentation/expressions/xpath30maps.xml), but I am unable to get past query compilation. Maybe I am missing some parameter or I use a wrong namespace, but I just can't find the right answer. This is my query code:
xquery version "3.0";
(: i have also tried http://www.w3.org/2005/xpath-functions/map, no difference :)
import module namespace map = "http://ns.saxonica.com/map";
map:get(map { 1 := 'aaa'}, 1)
invoked from command line:
"c:\Program Files\Saxonica\SaxonEE9.4N\bin\Query.exe" -s:play.xml -q:play2.xq" -qversion:3.0
The commands ends with error Cannot locate module for namespace "http://ns.saxonica.com/map"
When I leave out the module namespace map declaration, the error is Prefix map has not been declared, so I assume it must be.
Michael Kay has just posted a new blog entry with details on the Saxon Map implementation:
http://dev.saxonica.com/blog/mike/2012/01/#000188
You should use declare namespace instead of import module namespace for access to builtin functions. As far as I understand it, module import is for user-supplied modules only.
File map.xq:
declare namespace map="http://www.w3.org/2005/xpath-functions/map";
map:get(map { 1 := 'aaa'}, 1)
Works just fine:
> "C:\Program Files\Saxonica\SaxonEE9.4N\bin\Query.exe" -qversion:3.0 map.xq
<?xml version="1.0" encoding="UTF-8"?>aaa
I tried it with Saxon-EE 9.4.0.2J (the Java version) too, with the same effect.
Dunno if this helps, but the BaseX XQuery Processor also offers an implementation of Michael Kay's map proposal (still to be finalized by the W3): http://docs.basex.org/wiki/Map_Module

Resources