I've been attempting to implement a build solution using NPM scripts as opposed to Gulp/Grunt/etc as outlined here: http://substack.net/task_automation_with_npm_run and here: http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/. However, I'm struggling to integrate a clean and sensible approach for managing numerous Jade files in the build process.
The Jade CLI supports passing it a directory and outputting all of the deeply nested compiled Jade files. This is great, however, this completely flattens the folder structure. I'd ideally like to have Jade output the results whilst maintaining the directory structure. What's the best way to go about this?
Example folder structure:
package.json
src/
foo.jade
bar/
baz.jade
qux.jade
Running jade src -o build outputs:
package.json
build/
foo.html
baz.hmtl
qux.html
src/
Instead of:
package.json
build/
foo.html
bar/
baz.html
qux.html
src/
Not sure how I missed this but for anyone who should happen upon this in the future, the -H flag is your friend.
ex: jade src -H -o build
ref: https://github.com/jadejs/jade-cli/blob/master/index.js#L36
Related
I really like the folder structure as can be seen here when dealing with a React frontend and a some backend with express:
root
├── backend
| ├── node_modules
| ├── public
| ├── src
│ │ └── Server.ts
| ├── package.json
| └── tsconfig.json
├── frontend (created using create-react-app)
| ├── node_modules
| ├── public
| ├── src
│ │ └── Index.js
| ├── package.json
| └── tsconfig.json
I think that having separate packages with individual node_modules is reasonable since the frontend and backend are basically completely different things, e. g. they need different node modules. Also, this modular approach is visually appealing to me and the repository looks tidy.
However, I encounter a problem with this structure when I need to share content between the frontend and the backend. I added a shared folder under the root-of-project which contains its own project with its own tsconfig.json, package.json and so on. This approach is a mix of the approaches here and here. For the backend, this works totally fine: having set up the tsconfig.json appropriately (using TypeScript Project References and aliased imports), I can reference the file root/shared/src/myFile.ts like this:
import { myFunction } from #shared/myFile;
I created the React frontend using create-react-app. It's ok for me that alias imports don't work, so I would have to use (inside the src folder in frontend):
import { myFunction } from '../../shared/src/myFile';
Sadly, these imports from outside the src directory are not supported by create-react-app and I don't want to use eject since I have no experience with webpack and don't want to maintain all the configuration files on my own (that's why I used create-react-app in the first place).
I know I can move the shared content to the frontend's src directory. But this would mean, I had to add the tags needed for using Project References in TypeScript, e. g. setting composite to true, in the frontend's tsconfig.json which seems odd to me and feels more like a hack. I'd like to have a separate npm project with my shared content.
Since create-react-app does not inherently support imports from outside the src directory, I thought that maybe I'm getting the big picture wrong. Isn't the folder structure I use right now a valid way of how to setup a React project with a backend? What mechanism does create-react-app provide to link files between the frontend and the backend? I could also think of having a root project with a src folder and inside of that the two folders backend and frontend. But this means, that we'd have one shared node_modules folder in root.
It's my first project with React and I'd love to get to know some best practicese for this kind of architectural problem. Some links to trustful resources where project structures for full-stack React development are explained would be really helpful. Thank you 😊
It's perfectly reasonable to want to share code between your front and back end. It's one of the reasons to code in javascript instead of Ruby or PHP.
You can accomplish exactly what you want by using yarn instead of npm and yarn workspaces: https://yarnpkg.com/lang/en/docs/workspaces/. At the top level you set up three modules/packages in your package.json (make sure you name the workspaces correctly in their respective package.json files):
"workspaces": {
"packages": [
"backend",
"frontend",
"shared"
]
},
Once you do, you can import shared code in your CRA app or your back end simply like this:
import { myFunction } from 'shared/src/myFile';
The drawback is that you can't import react components from the shared directory into frontend as long as you are using CRA. This won't affect you now since you only have one react app. Should you need to share react components among multiple projects, look into some on the suggestions above like bit.dev.
ADDENDUM!!! It's now possible to use CRA and yarn workspaces to share React code, if you replace CRA with CRACO. All you do is create another workspace with the shared react code. Then create a symbolic link in each module where you want to access it:
root
├── fontend-one
| ├── symbolic link to frontend-shared
├── frontend-two
| ├── symbolic link to frontend-shared
├── frontend-shared
Each of the CRA front end modules modules also requires a craco.config.js file where you tell web-pack not to follow symbolic links:
module.exports = {
// ...
webpack: {
configure: {
resolve: {
symlinks: false
}
}
}
};
You import from shared-frontend normally:
import { myFunction } from 'shared-frontend/src/myFile';
It's a pretty lo-fi solution but has proven robust for the year we've been using it.
Architecture is a tricky one, everyone has a different opinion and every option has pro and cons.
Personally I believe its best to separate the backend and frontend into sperate projects and keep them that way. Now as JavaScript/React/Node encourage component-based approaches a really nice way of sharing code between them is Bit.dev.
https://bit.dev
I am currently using it to share components and functions between three web apps and a few Node microservices.
A good structure for React app can be found here, this one works well and scales nicely:
https://hackernoon.com/fractal-a-react-app-structure-for-infinite-scale-4dab943092af
As for Express, there are so many ways to structure the project but personally recommend a folder for your Routes, a folder for your Controllers, this is where the logic for Routes live. Then go from there. Check this link out:
https://www.freecodecamp.org/news/how-to-write-a-production-ready-node-and-express-app-f214f0b17d8c/
Depending on what your building you may not even need a full backend you can check out the JAMStack here for more info:
https://jamstack.org
I would consider separating them though as the project scales it makes it much easier to manage. You can release your front end on something like Netlify and then use something like AWS or Azure to host your Node/Express server.
Having separate sub-projects for frontend and backend makes perfect sense due to vastly different dependencies. Mixing it up increases disk space consumption in production deployments and goes against security guidelines. Your folder structure is reasonable (except for public/ subfolders I'm unsure about, maybe I'm missing something).
The approach import { myFunction } from #shared/myFile; is fine. Just don't use CRA.
For a project with a single frontend and a single backend there is no need for a shared\ top-level folder because the frontend is the only source of 'UI truth' (e.g. the source of types and components related to UI) that is consumed by the frontend and the backend is the only source of 'API truth' consumed by both frontend and backend. With this arrangement only #backend/api_shared_stuff needs to be shared.
Some links to trustful resources where project structures for full-stack React development are explained would be really helpful. On the one hand, usually project authors have to explain plenty of other things and on the other hand keep the documentation (typically a README) reasonably concise. You may find that providing a justification/explanation why the subdirectory structure is this and not that was not the top priority.
We are trying to separate our project into "sub modules" within single repo, but keep things like webpack, express server global, so assume structure like this
package.json
server.js
index.js
node_modules/
public/
index.html
dashboard.js
onboarding.js
dashboard/
index.js
package.json
node_modules/
components/
assets/
onboarding/
index.js
package.json
node_modules/
...
idea here is to keep build / routing / server logic at root lvl and separate modules like dashboard and onboarding into their separate folders and allow them to use their own node modules.
Will this work? Will node modules be included correctly?
webpack will build assets to public/ folder, with some vendor assets and several entry points i.e. all index.js files
What you are proposing will work fine and compile as you expect. NodeJS will initially look for modules included in your modules 'node_modules' sub-directory and then work up the ladder.
I run babel against my source files, i want to output one single file, with all the relative imports injected inside the file.
Source structure
src
│ index.js
│ relative-file.js
│
└───some-folder
another-relative-file.js
the index file requires relative-file, and the relative-file requires another-relative-file.
Expected output
index.js with no relative requires, everything is injected inside this one file.
Actual output
index.js with require('./relative-file') inside.
Tried babel-cli commands
babel src --out-file distribution/index.js
output a dir will put output multiple files requiring each other just like the source.
babel src --out-dir distribution
I don't think babel helps with eliminating requires. You need to use a bundler like webpack in combination with babel to achieve what you want.
I have two Angular2 projects using webpack as module bundler and typescript.
Aiming to share code between, I split some of the source code and created a symlink to this 'external' source code from each of this two projects.
After doing this the "symlinked code" can not resolve the imports properly.
below a "hello world" project to shows my concerns.
https://github.com/datracka/angular2-symlink-issue
This project runs straight forward BUT if you remove the given src folder and create a symlink to another src folder with the same source code BUT located at /another/path/src then you get a compiler error:
ERROR in .-shared/src/main.ts
Module build failed: TypeError: Path must be a string. Received undefined
at assertPath (path.js:7:11)
at Object.dirname (path.js:1326:5)
at ensureTypeScriptInstance (/Users/vicensfayos/Projects/angular2-abc/node_modules/ts-loader/index.js:156:103)
at Object.loader (/Users/vicensfayos/Projects/angular2-abc/node_modules/ts-loader/index.js:403:14)
So my question is: what I am missing with symlinks when I "distribute" the source code in another folder out of the project folder itself?
My guess is about configure properly resolving object in webpack https://webpack.github.io/docs/resolving.html to override the node.js loading node_modules algorithm https://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders but not luck.
Hopefully somebody can point me in some direction.
I found the answer.
My guess was right. it was about how nodejs resolve the dependencies. https://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders
The symlinked code is trying to find the dependencies moving up all the way failing until it finds node_module. But nothing is there. node_module is in the parent project.
Therefore the solution is create another symlink from the symlinked code to the node_modules folder of the parent project to resolve the dependencies.
I have a similar setup but decided to add a path to my tsconfig.json in my main app:
"paths": {
"*": ["*", "node_modules/*"]
}
All the modules required by the source code in the shared symlinked folders are in the main app's node_modules folder. This tells the compiler to look in the main app's node_modules folder before trying to find a node_modules folder further up the tree.
I am using Gulp to build a deployable build for an application. I would like to cache-bust all of my .js and .css files so that when a new build is deployed, users will need to retrieve the new "cache-busted" files. For example, if an app.js file is stored in the browser's cache, I would like to have the ref to app.js in my index.html look something like this:
<script src="app/js/app.js?v=1.2"></script>
and so on for all relevant files I would like to cache bust.
Some other questions related to this problem I have:
1) How can I tell that these files are actually getting cache busted properly?
2) Is there a better way to approach this?
Here is what I am trying so far:
//compile index.html, app, vendor
gulp.task('compile-dist', function(){
var revAll = new RevAll();
gulp.src('../../backend-angular-seed/app/**')
.pipe(gulp.dest('../dist/app'));
gulp.src('../../backend-angular-seed/vendor/**')
.pipe(gulp.dest('../dist/vendor'));
gulp.src('../index.html')
.pipe(gulp.dest('../dist/'));
})
This code takes all of the code from my app/ directory (which is a result of my compiled code from my master/ directory) and builds a dist/ directory with all of my js, css, and vendor files.
After this build I have a dist/ directory that looks like this:
/dist
/css
|_app.css
/img
/js
|_ app.js
|_ base.js
/vendor
index.html
I have tried using a few different methods on modifying this dist directory to effectively have it bust the cache. I tried using gulp-cachebust as well as gulp-rev-all, but I believe both of these tools are a bit overkill for what I am trying to do.
Ideally, through Gulp, I would like to go into the index.html file made from the Gulp build, and modify all of my script tags to append the query string of "?v=1.0" on the end of all files I would like to cache bust per deploy build.
Any answers/suggestions would be greatly appreciated. Thanks so much!!!
If appending query string is all you want then i recommend using gulp-cache-bust.
var cachebust = require('gulp-cache-bust');
gulp.src('./dist/index.html')
.pipe(cachebust({
type: 'timestamp'
}))
.pipe(gulp.dest('./dist'));
Here is the turorial for it: https://www.npmjs.com/package/gulp-cache-bust