I have a typescript monorepo setup that uses npm workspaces and I want to be able to import subpaths down to any individual typescript file of #package/shared in #package/client and #package/server while skipping the src folder. One solution is simply removing the src folder and moving every subfolder up the hierarchy but that feels like a hacky solution. I tried using wildcards in the exports (e.g. "./*": "./src/*", "./": "./src/*.ts") but either they're not working or they only work partially (moduleResolution is set to "NodeNext")
For example, with the following folder structure of the monorepo
.
├── package.json
└── packages/
├── shared/
│ ├── package.json
│ └── src/
│ ├── index.ts
│ ├── types/
│ │ ├── index.ts
│ │ ├── foo-type.ts
│ │ └── bar-type.ts
│ └── constants/
│ ├── index.ts
│ ├── foo-const.ts
│ └── bar-const.ts
├── client/
│ └── ...
└── server/
└── ...
I want to be able to import any typescript file in the shared package while skipping src
import { ... } from "#package/shared"
import { ... } from "#package/shared/types"
import { ... } from "#package/shared/types/foo-type"
import { ... } from "#package/shared/types/bar-type"
import { ... } from "#package/shared"
import { ... } from "#package/shared/constants"
import { ... } from "#package/shared/constants/foo-const"
import { ... } from "#package/shared/constants/bar-const"
// shouldn't work!
import { ... } from "#package/src/shared/..."
I'm using the verion 2.7 of Parcel for bundling my client side javascript. I have a index.ts where I group all my code. In some cases I have to use dynamic import statements:
example:
const { Menu } = await import('./Menu');
The issue that I can't solve: after each update on Menu.ts, Parcel creates a newly hashed Menu.[hash].js file instead of updating it.
npm run watch:js:
"watch:js": "parcel watch --no-hmr ./public/ts/index.ts --dist-dir ./public/js --public-url ./"
public folder structure:
.
└── public/
├── [...]
├── js/
│ ├── index.js
│ ├── index.js.map
│ ├── Menu.[hash-1].ts **! that's an issue !**
│ └── Menu.[hash-2].ts **! that's an issue !**
└── ts/
├── [...]
├── index.ts
└── Menu.ts
My project was working 100% fine until I pushed it to Github & cloned it, suddenly I am experiencing a myriad of "Module not found: Can't resolve..." import errors.
Here's 1 example:
Module not found: Can't resolve './components' in '..src\layouts\Main'
Main.js
import { Sidebar, Topbar, Footer } from "./components";
Folder structure
src
├── layouts
│ ├── Main
│ │ ├── components
│ │ ├── Footer
│ │ ├── Footer.js
│ │ ├── Sidebar
│ │ ├── Sidebar.js
│ │ ├── Topbar
│ │ ├── Topbar.js
│ │ ├── Main.js
Update:
How to import redux actions?
src
├── redux
│ │ ├── actions
│ │ ├── dataActions.js
│ │ ├── userActions.js
| | - store.js
| | - types.js
Any help would be greatly appreciated!
You can only import with the component name, when you have an index.js file in the folder Footer.
import { Sidebar, Topbar, Footer } from "./components";
You need to have this folder structurue:
src
├── layouts
│ ├── Main
│ │ ├── components
│ │ ├── Footer
│ │ ├── index.js
│ │ ├── Sidebar
│ │ ├── index.js
│ │ ├── Topbar
│ │ ├── index.js
│ │ ├── Main.js
Updated, because question was updated:
For different redux actions, you can have an index.js file in the actions folder, which does the importing of the actions. Like so:
Within actions create index.js with the actions:
import { dataActions } from './dataActionts'
import { userActions } from './userActions'
Premise
Let's say I have two different AMD-based AngularJS apps, each of them with their own sets of controllers, directives, services, etc. Each of them are bundled in their own dist/{app-name}.min.js and loaded in <script> tags in the same HTML page (this is all in the context of a CMS that then contains these apps among other things)
Now the apps end up sharing some of the services, directives, and vendor libraries like angular itself, moment, jQuery, etc, so I've made another folder for all of these resources, which results in a bundle that will be added to the page before the js bundles of the apps:
<script src="/some-path/dist/shared-resources.min.js"></script>
<script src="/some-path/dist/first-app.min.js"></script>
<script src="/some-path/dist/second-app.min.js"></script>
This is the resulting folder structure:
.
├── shared-resources/
│ ├── dist/
│ ├── src/
│ │ └── common/
│ │ ├── directives/
│ │ ├── modules/
│ │ ├── services/
│ │ └── vendor/
│ └── build.js
│
├── first-app
│ ├── dist/
│ ├── src/
│ │ ├── first-app/
│ │ │ ├── controllers/
│ │ │ ├── modules/
│ │ │ ├── services/
│ │ │ ├── directives/
│ │ │ └── app.js
│ │ └── first-app.js
│ └── build.js
│
└── second-app
├── dist/
├── src/
│ ├── second-app/
│ │ ├── controllers/
│ │ ├── modules/
│ │ ├── services/
│ │ ├── vendor/
│ │ └── app.js
│ └── second-app.js
└── build.js
This is an example of what the build.js file for the common modules looks like
({
baseUrl: 'src',
removeCombined: true,
out: 'dist/shared-resources.min.js',
paths: { // forcing a `common/{modulename}` convention
'common/jquery': 'common/vendor/jquery.min',
'common/moment': 'common/vendor/moment.min',
'common/angular': 'common/vendor/angular/angular.min',
},
shim: {
'common/angular': {
exports: 'angular',
}
},
include: [
'common/modules/vendors', // Just a bundle of every vendor modules
'common/directives/common-directive',
'common/services/common-service'
],
})
Now my intention was to have all the shared modules being namespaced with common/, so each of the apps could require common/angular, common/directives/common-directive, and so on, and then exclude the common path when creating their bundle (since all the common modules are already present in the shared-resources.js bundle), for example:
// first-app/src/first-app/controllers/app-controller.js
define([
'first-app/modules/controllers',
'first-app/services/app-service',
'common/services/common-service'
], function (controllers) {
'use strict';
controllers.controller('AppController', ['CommonService', 'AppService', function (CommonService, AppService) {
CommonService.call();
AppService.call();
}]);
});
// first-app/build.js
({
baseUrl: 'src',
out: 'dist/first-app.min.js',
paths: {
'common': 'empty:'
},
name: 'first-app',
deps: ['first-app/app']
})
Problem
The problem is how these two apps, which again are both loaded on the page (this can't be avoided), are supposed to correctly look up these common modules.
Given that each of the apps have obviously a different baseUrl, they are put in different RequireJS contexts, otherwise the baseUrl of the second app would override the baseUrl of the first one, causing the incorrect loading of its modules:
// first-app/src/first-app.js
require.config({
context: 'first-app',
baseUrl: 'first-app/src',
})(['fist-app/app']);
// first-app/src/second-app.js
require.config({
context: 'second-app',
baseUrl: 'second-app/src',
})(['second-app/app']);
But putting them in context then causes the look up for the common modules to fail, as the modules are looked in the baseUrl of the context. Actually this happens only for the second app (second in order of loading), while the first app to be included in the page can load the common modules fine
Question
So how should I make the apps to correctly share the common modules? Am I approaching this wrong? Should I use something else than RequireJS?
The context feature of RequireJS is really meant to be used to handle a case where you have to load two conflicting applications on the same page and the conflict cannot be resolved otherwise. The way you've written your code so far may have led you to want to have two baseUrl values, but there is nothing in your question that indicates that you must have two baseUrl values. There are ways to avoid it:
Modules that are part of a logical set of modules should load each other with relative paths. For instance, the module you give as example could be:
// first-app/src/first-app/controllers/app-controller.js
define([
'../modules/controllers',
'../services/app-service',
'common/services/common-service'
], function (controllers) {
paths can be set to make it look like a module is directly under baseUrl even if it is not. You could have:
paths: {
'first-app': 'first-app/src'
'second-app': 'second-app/src'
}
and yes, loading first-app/app will work. RequireJS will transform the path to first-app/src/app.js.
I'm trying to setup a glob array for my javascript concat build task in gulp. The directory structure looks as follows:
├── about
│ └── about.js
├── assets
├── contact
├── core
│ ├── navbar
│ │ ├── navbar.js
│ │ └── navbar.test.js
│ ├── routing.js
│ ├── routing.test.js
│ ├── utils.js
│ └── utils.test.js
├── generated
│ ├── footer.js
│ ├── header.js
│ └── templates.js
├── home
├── app.js
└── config.js
The order of the files is important:
generated/header.js
app.js
any of the *.js files, except those here below
generated/templates.js
generated/footer.js
I've wildly tried all kinds of wildcards combination, but the globbing isn't strong with me.
var inputFiles = [
'generated/header.js',
'app.js',
'!(generated)**/*.js', // <=---- ???
'generated/templates.js',
'generated/footer.js',
'!**/*.test.js'
];
So how do I include all *.js files except those from a subdirectory?
Thanks.
The best I came up with:
var gulp = require('gulp');
var tap = require('gulp-tap');
gulp.task('default', function() {
return gulp.src([
'generated/header.js',
'app.js',
'*.js',
'./!(generated)/**/*.js', // <- All subdirs except 'generated'
'generated/{templates,footer}.js',
'!**/*.test.js',
'!node_modules/**'
]).pipe(tap(function(file) {
console.log(file.path);
}));
});
Running it:
∴ glob-test gulp
[20:07:51] Using gulpfile ~/Desktop/glob-test/gulpfile.js
[20:07:51] Starting 'default'...
/Users/heikki/Desktop/glob-test/generated/header.js
/Users/heikki/Desktop/glob-test/app.js
/Users/heikki/Desktop/glob-test/config.js
/Users/heikki/Desktop/glob-test/gulpfile.js
/Users/heikki/Desktop/glob-test/about/about.js
/Users/heikki/Desktop/glob-test/core/routing.js
/Users/heikki/Desktop/glob-test/core/utils.js
/Users/heikki/Desktop/glob-test/core/navbar/navbar.js
/Users/heikki/Desktop/glob-test/generated/templates.js
/Users/heikki/Desktop/glob-test/generated/footer.js
[20:07:51] Finished 'default' after 326 ms
The main trick is avoiding the "!" character at the beginning of glob when including files.
https://github.com/isaacs/minimatch#comparisons-to-other-fnmatchglob-implementations
"If the pattern starts with a ! character, then it is negated."
ps. Placement of the negated globs doesn't matter. They are always moved to the end behind the scenes.