webpack require with dynamic path - javascript

My colleague put something like this in our code:
const information = require('../relative/path/' + tag + '.json');
The funny thing is that it works, and I don't really see how.
I have created this minimal project:
$ head *.json main.js
==> 1.json <==
["message #1"]
==> 2.json <==
["message two"]
==> 3.json <==
["message III"]
==> package.json <==
{
"dependencies": {
"webpack": "^5.38.1"
"webpack-cli": "^4.7.2"
}
}
==> package-lock.json <==
...
==> main.js <==
const arg = process.argv[2] ? process.argv[2] : 1;
console.log(require(`./${arg}.json`)[0]);
when I run the original program, I get this:
$ node main.js 1
message #1
$ node main.js 2
message two
$ node main.js 3
message III
so now I compile with webpack
$ node_modules/.bin/webpack ./main.js
and it creates a dist directory with a single file it in, and that new bundled program works too:
$ node dist/main.js 1
message #1
$ node dist/main.js 2
message two
$ node dist/main.js 3
message III
and when I look inside the bundle, all the info is bundled:
When I remove the require from the program, and just print the arg, the bundled program is a single line.
So how does it do it?
somehow calculate every possible file?
just include everything from the current directory down?
Funny thing is in my simple example, package.json ended up in there too, but in the real one that gave me the idea, it didn't.
Does anybody know how this works?
I mean the simple practical answer for me is, never put variables in require... but I am still curious.
PS the real one is a web project. just used node and args for the example

Webpack always bundles all require'd files into the final output file (by default called bundle.js). You cannot require anything that was not bundled.
If you require something that is not a constant, as you pointed out, it might lead to some trouble. That is why eslint has a no-dynamic-require rule for that. But if you know what you are doing, everything is just fine.
Webpack uses some heuristics to support non-build-time-constant values (i.e. expressions) for require. The exact behavior is documented in webpack's documentation on dependency management.
As explained in that link, your require('../relative/path/' + tag + '.json') will lead webpack to determine:
Directory: ../relative/path
Regular expression: /^.*\.json$/
And will bundle all files matching that criterion.
When your require call is executed, it will provide that file that matches it exactly, or throw an error if that file was not bundled.
Important: This means, of course, that you cannot add files after bundling. You must have files in the right place, before bundling, so they can be found, added and ultimately resolved by webpack.
Also note that often times, you don't need to write your own webpack experiments. Webpack has plenty of official samples. E.g. your case is illustrated exactly by this official webpack sample.

Related

Bit will not find modules located within tsconfig's srcDir property

My bit build cannot locate various modules and fails:
$ bit build
Command failed: node /Users/me/Documents/repos/my-project/.git/bit/components/compilers/angular/bit.envs/0.2.0/node_modules/ng-packagr/cli/main.js -p ng-package.json -c tsconfig.json
ERROR: button/button.component.ts(13,38): error TS2307: Cannot find module 'app/services/my-service-a.service'.
button/button.component.ts(14,25): error TS2307: Cannot find module 'app/services/models/'.
etc . . .
I am thinking that it cannot find modules that live within src/app that are just referenced use app, eg:
import { IMyInterface } from 'app/services/models/';
This works in the project because tsconfig.json contains the property
"srcDir": "src"
so app/ within the component actually references src/app
However, the first line of the error seems to be the full bit command with some default settings explicitly written out. There is written:
-p ng-package.json -c tsconfig.json
Well, I have no idea about ng-package.json. This is not in my project. But the tsconfig.json which contains the srcDir property lives at the same level in my project as I ran bit build from, so the -c argument looks correct.
How can I instruct Bit to find modules located within srcDir?
Also, I can't find a tag for Bit, so if anyone can help me out with that, thanks. Further, if any maintainers of Bit read this, I need to tell you that your name is really difficult to Google errors for. It's too short and far too common a word. Any search advice in this area would be welcome.

Jest "No tests found, exiting with code 1" error on Windows 10 in React Redux application

I am attempting to run Jest on my project. I am on a Windows 10. I only have one test in one test file.
In package.json:
"test": "jest"
My directory structure:
src/
app/
routeName/
redux/
action.tests.js
My output:
No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
In C:\Users\myUsername\Documents\myApp
47 files checked.
testMatch: **/__tests__/**/*.[jt]s?(x), **/?(*.)+(spec|test).[tj]s?(x) - 0 matches
testPathIgnorePatterns: \\node_modules\\ - 47 matches
testRegex: - 0 matches
Pattern: - 0 matches
npm ERR! Test failed. See above for more details.
According to the documentation here, Jest should look for anything that has test.js in the name.
I have also tried tests.js and that didn't work either.
I created a folder in the root of the project and put a test in there as __tests__/tests.js and that did work, but I do not want it placed there.
I have seen several tickets and questions about questions that are superficially similar, but all of those involve more complex configurations, or bugs that were supposedly patched already. I have no special configurations set. The documentation says this should work. Tutorials I have read for Jest include the exact setup I am currently using.
I am using Babel and Webpack. I installed the jest and babel-jest packages. I also added jest to the ESLint environment.
[edit] updated to properly document my problem, which I answered below. I lost track of my file naming.
I am a bloody idiot and I didn't pay attention to the details.
Jest is looking for test.js specifically. Not testS.js. My files were labeled as tests.js. It worked inside __tests__/ because Jest just looks for anything inside there.
I got it working just fine now, and it shall remain up as a testament to me not looking at the specifics of the regex matches.
I had the same Problem with a React-App. Make sure, that the jest config file has the correct file pattern to find the tests:
// jest.config.js
module.exports = {
testMatch: [
'<rootDir>/src/**/*.test.js',
'<rootDir>/src/**/*.test.jsx',
],
...
}
From my side, I was getting this error because I had placed myself (cd) in the directory where the chromeDriver was installed, so as not to have to add its path to $Path. After I added chromeDriver to $Path, and placed myself in the directory of my project, everything went fine.
No tests found, exiting with code 1
All I had to do was npm install.
Then I hit the Debug link at the top of my test. The test was found and execution stopped at the breakpoint. A simple solution to a very frustrating problem.
You just need to change the name of the file. For example
if you have a customer.js or customer.ts file and you want to test it. Create a new file name is customer.test.js or
customer.test.ts after npm test it will test the file which just for testing .
I had the same problem, I wanted to run my tests inside drone CI pipeline and had the same error what solved my problem was simply adding workspace to my project.
check if it is small case like filename.test.js.
I made a mistake ComponentName.Test.js and got error, fixed it by ComponetName.test.js

"Uncaught ReferenceError: require is not defined" with Angular 2/webpack

I am working an HTML template from a graphic design company into my Angular 2 project using node and webpack.
The HTML pulls in various scripts like this:
<script src="js/jquery.icheck.min.js"></script>
<script src="js/waypoints.min.js"></script>
so I am requiring them in my component.ts:
var icheckJs = require('../js/jquery.icheck.min');
var waypointsJs = require('../js/waypoints.min');
There are several other scripts too and some SASS which appears to be working correctly.
webpack is happy and build it all and an 'npm start' is successful too. However, when it reaches the browser, I get this complaint:
Uncaught ReferenceError: require is not defined node_modules/angular2/platform/browser.js:1 Uncaught ReferenceError: require is not defined
which is actually thrown by this line from url.js:
var punycode = require('punycode');
Is this a CommonJs require? I hadn't used this in web development before a few weeks ago so I'm still untangling the various requires from webback, CommonJs et at.
An extract from my webpack.config.js for the .js loader looks like this:
{ test: /\.js$/, loader: 'script' }
How do I work around this error?
WebPack can do this alone. You need to make sure you load the initial chunk first using a script src tag. It will typically be the value of the entry: key in the WebPack config with -bundle appended. If you're not doing explicit chunking, your entry chunk should be both an initial and entry chunk and have the WebPack runtime in it. The WebPack runtime contains and loads the require function before your code runs.
Your components or whatever you're requiring need to be required from the entry file since your scripts will start there. Basically, if you're not explicitly chunking, the entry point JS file is the only one you can include with script src. Everything else needs to be required from it. What you include will typically have bundle in the JS filename. By default, it should be main-bundle.js.
For anyone that is looking for an answer but the above doesn't work:
Short
Add or Replace current target in webpack.config.js to target: 'web'
A bit longer
Webpack has different targets, if you've experimented with this and changed your target to node it will use 'require' to load chuncks.
The best thing is to make your target (or to add) target: 'web' in your webpack.config.js. This is the default target and loads your chuncks in a way the browser can handle.
I eventually found this solution here.
You can do this in one line assumed that you have
the bundle in dist/bundle.js
the source file client code that will render the page in the browser in
client/client.js
webpack && webpack ./client/client.js dist/bundle.js \
&& webpack-dev-server --progress --color
You need to run webpack again since if some sources in the library change you will get the last changes then in the dist/bundle.js package (of course you can add like a grunt file watch task for this). webpack-dev-server will run the server then.

node app with coffeescript and gulp

I'm pretty new to node, but I'm trying to dive in by taking a framework that's already built (skeleton) and converting it to coffeescript.
So this has a config folder, with config.js, passport.js, and utils.js files... also, obviously, in the root, app.js. He's using gulp, so there's a gulpfile.js. I wanted to convert these files to coffeescript, and not just the user js files. Is that bad practice? I've added gulp-coffee as a devDependency, and coffee-script as a dependency.
Upon rebuilding the aforementioned files, and renaming them...
[12:23:40] 'coffee' errored after 61 μs
[12:23:40] Error: Invalid glob argument
at Gulp.src (/Users/brett/Dropbox/Apps/mean_projects/skeleton/node_modules/gulp/node_modules/vinyl-fs/lib/src/index.js:17:11)
... and further down
[gulp] [nodemon] starting `coffee --debug app.coffee`
/Users/brett/Dropbox/Apps/mean_projects/skeleton/config/config.coffee: line 1, col 1, Expected an assignment or function call and instead saw an expression.
/Users/brett/Dropbox/Apps/mean_projects/skeleton/config/config.coffee: line 1, col 13, Missing semicolon.
/Users/brett/Dropbox/Apps/mean_projects/skeleton/config/config.coffee: line 3, col 1, Expected an identifier and instead saw '#'.
That shows config.coffee, and there are blocks of errors for each of the files that I converted from js to coffee (app, app_cluster, gulpfile, utils, passport, etc).
Any help on the topic would be good... I've been reading quite a few articles (some that hate coffeescript) but nothing that really shows how to handle this.
If you use gulp 3.7+, then gulpfile.coffee is supported out of the box. No need to do any extra setup.
If you have to use an earlier you can bootstrap coffeescript, by just putting this in it:
// Note the new way of requesting CoffeeScript since 1.7.x
require('coffee-script/register');
// This bootstraps your Gulp's main file
require('./Gulpfile.coffee');
Then you can put you setup in gulpfile.coffee.
Is that what you meant?

Node.js package self-reference

Can package require itself and its subsystems?
For instance there is module:
src/deep/path/to/module.js
which need to require
src/another/module.js
Instead of:
require('./../../../another/module.js');
Can one just:
require('<self>/another/module.js');
?
For instance this might be useful in testing: test unit can reference its test object without long up-and-down-style path.
I have two considerations (but they do not satisfies this issue completely):
If package is already in node_modules folder it can reference to itself by its
canonical name (that in its package.json).
Package can create symlink to itself in its own node_modules folder (sic!). Haven't try it yet, possible will lead to infinite loop in some resolving cases.
Solution 1
Split it to different sub-projects, put each one into different folders. As an example:
sub.project.1/
sub.project.2/
in sub.project.1/
# cd ../sub.project.1
npm link
# cd ../sub.project.2
npm link sub.project.1
Then in sub.project.2 you can do it simply:
var something = require("sub.project.1")
This can remove the '../../...' relative path.
Note: it can be done in same folder/project, by doing this,
in the sub folders, the project self can be easily referred.
For example when both sub.project.1 and sub.project.2 replaced by my.project. And of course, all the names should be the name in package.json initialized by npm.
Solution 2
Create a link in the folder node_modules/
# cd node_modules
ln -s .. myProjectRootDir
#
# where: .. : means parent directory in linux shell
# '#' means comments in linux shell
#
Then it can be used under same level directory trees:
var something = require("myProjectRootDir/path/to/js/file")
Thus the "../../..." can change to path read more easily.
And if myProjectRootDir happens to be the project name and
package name in package.json, it's ok.
Solution 3
There are npm packages: require-self, install-self,
they do the similar things.
Solution 4
Write a new .js file where it's easy to require,
then put all the annoying relative references into it.
For example write it at node_modules/mymods.js
// mymod.js
module.exports.mod_one = require("../path/to/mod/one.js");
//...
Then require('mymod') can gives all the other modules.
This is not the best solution, all references of requiring
need to be doing by hand. But it's a single file, so it's
manageable, and centralize the references for future deployments.
One of the cons of this solution is, if you put it in
node_modules/ folder and this folder is ignored in git repository, you need to take care when pushing or branching the git repo.
When deleting the node_modules folder, the file can also be deleted by accidents.
There could be more solutions I don't know.
Well you can shorten it a little bit. You don't need the leading ./ in this case
require("../../../another/module.js");
And a little further by removing the trailing .js
require("../../../another/module");
Another answer is suggesting the use of process.cwd() but be very careful with this. Your require calls will only work if the app is initialized from the same directory.
From the sounds of it though, 4 directories is already pretty deep. You might want to considering fragmenting your large project into smaller, single-purpose modules. We would need more information on the project to know if that was the right decision though.
I often use process.cwd() to make things like this a little more manageable. This returns where the node application is actually running from and lets you create the path in a little cleaner fashion.
Something maybe like var x = require(process.cwd() + '/lib/module')
Without seeing exactly what you're trying to do; I'm not sure if this will be helpful, but you can do things like var connect = require('express/connect') as well. Basically you can pass an installed local module, and then create paths off of it as well.

Categories

Resources