Can I tell babel to replace an output directory? - node.js

The Situation
I'm working on a project in Node.js and using babel to transpile my code. My package.json has a build command defined like this:
"scripts": {
"build": "yarn run babel src -d lib",
},
The Problem
This transpiles fine, taking the content of src and outputing the result to lib, but there are two issues:
lib will contain old files from past transpiles even if they no longer have a matching file in src.
Babel will not rename files with a changed case if my OS is case insensitive. For example, if I had transpiled a file named src/Foo.js and later renamed it to src/foo.js then future transpiles will still be named lib/Foo.js
The Question
Can I tell babel to wipe away the contents of the lib directory before transpiling or do I need to just insert a rm into the build script?

Babel does not have functionality to do this. It is very common to use a rimraf or some other means to delete the directory before running Babel. rm directly is certainly also an option, but that does get more complicated if you want to support Windows too, hence the rimraf usage.

Babel CLI has a flag to remove the output directory: --delete-dir-on-start
Couldn't find any online documentation for it, but it's listed in babel --help:
--delete-dir-on-start Delete the out directory before compilation
Was added in this PR back in 2017.

Related

Within in a monorepo, is it possible to configure a package to 'use the uncompiled code if you can'?

I'm playing around with Yarn 2, and I want to do something like this.
I have a monorepo of the structure:
/
packages/
shared-ts/
package.json
src/
lib*/
app-ts/
package.json
src/
lib*/
app-js/
package.json
src/
lib*/
where lib* denotes that the folder is gitignored, but is where the compiled code will live.
In this example, I have a dependency library shared-ts that is used by two apps, app-ts and app-js.
The conventional approach
The conventional approach to configuring a monorepo like this, is that in shared-ts I would have a package.json like:
"main": "lib/index.js"
"scripts" : {
"build": "tsc"
}
Where the build script will build index.js and index.d.ts into the lib folder.
When both app-ts and app-js then resolve the package, they look in the lib folder and find the index.js and in app-ts's case - the index.d.ts.
This works fine, except that the developers need to remember to run the build script if they have made changes to shared-ts in order for the changes to propagate across.
Where this could potentially become problematic is where there are many layers of dependencies.
Attempted work around 1 - point main to src/index.ts.
I can change shared-ts package.json to
"main": "src/index.ts"
"scripts" : {
"build": "tsc"
}
This generally won't work, a plain node process won't be able to parse the syntax in the .ts file (eg. the import keyword).
Potential workaround - publishConfig
So something I'm considering, but haven't tried yet is, using the publishConfig
fields in the package.json
This field contains various settings that are only taken into consideration when a package is generated from your local sources (either through yarn pack or one of the publish commands like yarn npm publish).
"main": "src/index.ts",
"publishConfig": {
"main": "lib/index.js"
}
The idea being that:
When you publish a package to npm, lib/index.js will be used as main. 👍 code is ready for consumption, no compilation required.
If being used directly in the monorepo src/index.ts will be used as main. 😕 This kind of works as if you were running app-ts with ts-node for example.
However, where this starts breaking down is:
Running app-js in a development environment (where you don't have any additional syntax parsing set up).
Practical current best solution
My current best solution is to 'just give up on this 'no compile' aspiration' - if a developer makes changes to some code, they need to re-run build for the changes to propagate across.
How about using this?:
import someValue from 'some-package/src/index';
I can do this in my monorepo like the image below
I believe using nx will be good choice here. While it won't help you run the uncompiled code, it has pretty good features. In particular, you can automatically run the affected:apps on certain changes. For example, if you have a start command, it will run the start command for all the affected apps.
I wanted the same thing but had to compromise on the "Automatic compilation on changes" option in my JetBrains IDE.
It allows me to debug with ts-node as well as run the code using the native node binary.

Manually created subfolder from /src is missing in /dist when building

I created a subfolder in /src called /libs. When I run npm run build, the subfolder isn't included in /dist.
I'm assuming that I have to modify a build script? If so, which file would that be?
Edit #1
This all stems from trying to require a custom module located in src/libs from my controller. I've tried various patterns: ../libs/module_name, ./libs/module_name. The only way to have it work was to hard code the path from the root (i.e. /home/me/app/src/libs/module_name).
If I do: console.log(__dirname) in the controller that is attempting to require the module from /lib, I see a reference to /dist. I went looking into /dist and /libs wasn't there.
lb-tsc is a thin wrapper for TypeScript compiler (tsc), you can find the source in loopback-next:packages/build/bin/compile-package.js
Among other options, it provides a new flag --copy-resources to copy non-TypeScript files from src to dist. I think it may work equally well (if not better) as your cp -r solution.
"scripts": {
...
"build": "lb-tsc es2017 --outDir dist --copy-resources"
...
}
Personally, I would use a different solution:
use src only for TypeScript files to be compiled
put JavaScript sources and other files into a different directory, e.g. lib (instead of src/lib).
With the help of a colleague, I figured it out. In package.json, I appended a copy command to bring the libs folder into dist in the build section.
"scripts": {
...
"build": "lb-tsc es2017 --outDir dist && cp -r src/libs dist",
...
}
For those using Nest CLI, please note that it also does not automatically move your "assets" (non-TS files) to the dist folder during the build process.
For these non-TS files you just need to add them to the "compilerOptions": {}
property in the nest-cli.json file.
"compilerOptions": {
"assets": ["**/myfolder/**"]
...
}
The syntax "**/father-folder/**" causes all folders & files in myfolder to be included in the distribution folder (dist)
My resource for this was from Derryl Thomas
Link to NestJS documentation on assets : Link...

Use wildcards in npm run task for tslint so files and subfolders are linted

I am using the npm scripts property / object to validate / lint my TypeScript files in my Angular2 project, you can see my npm run tslint task below:
"scripts": {
"tslint" : "tslint -c tslint.json app/src/**/*.ts -e app/src/**/*.spec.ts",
},
This all seems good as it is linting my actual app files, but not my tests (I will remove this later). However my real problem is that my main.ts file which is in the app/src/ folder and not one of the many subfolders app/src/*sub-folder* is not being included in the linting. How can I improve the wildcard above or tslint command to include typescript files in my app/src folder as well as those in any other subfolder?
If I haven't made myself clear please say so and I'll re-phrase the question.
Many thanks

How do I setup Babel 6 with Node JS to use ES6 in my Server Side code?

I have read several times the documentation provided at :
Node API Babel 6 Docs
I'm starting out learning pg-promise following the Learn by Example tutorial and would prefer to work with ES6 and transpile to ES5 with Babel but am unsure of a few things :
After installing babel-core, what preset do I use and where/how do I configure this to work?
The documentation was unclear to me about which file I put: require("babel-core").transform("code", options); into and what parts of that code are place holders. When I use that code, do I just use it one time somewhere and then I can use ES6 in every other file? How would this be achieved?
I read about this .babelrc file and would like to confirm if the actual filename is ".babelrc" or if that is just the file extension and where in relation to the root directory of my project do I put that file.. and how do I link to it?
If I'm using pg-promise should I be using ES6 and Babel or will running : npm install as described under the Testing section for pg-promise be enough and trying to use ES6 with this create more problems?
I was hoping to take advantage of let and const if the need came up during my server side development.
Is there a standard file structure for a node+babel+pg-promise server setup?
Edit
Worth noting that I have also read Node JS with Babel-Node and saw that using this should be avoided. The final answer at the very bottom didn't really make sense to me for similar reasons I'm having trouble following the actual documentation provided by Babel.
1.a What Preset is needed?
You will need to install Babel firstly with npm install babel-core --save-dev in the root directory of your project using a Terminal window like Command Prompt.
Once installed, you will need to install the es2015 preset with npm install babel-preset-es2015 --save-dev. Babel-Core is Promises/A+ Compliant but not ideal for usage due to poor error handling so a library such as Bluebird should be used instead for this purpose. In order to transpile, babel-core will still need to be installed and es2015 enables ES6->ES5 transpiling so you can use fancy things like let and const etc.
1.b Where to put require("babel-core");?
instead, use require("babel-core/register"); and place it inside your Entry file typically called, "server.js". The server.js file will need to use CommonJS (ES5) exclusively.
By using the "require" statement it will apply all relevant transforms to all code being required into the Entry file and all files being required/included into those files.
You point to the Entry file inside package.json under the "main": section.
Package.json is created when you initialise the project with npm init at the root directory of your project inside the Terminal Window
One approach to this would be :
Entry File - server.js
server.js - requires {babel-core and the main ES6 file : config.js/jsx/es6/es}
config.es6 - uses ES6 and has includes(requires) for all other project files that can also use ES6 as they get transpiled by being loaded into the "config" file which is being directly transpiled by babel-core.
2. What is .babelrc?
.babelrc is the filename and should be placed in the same folder as your package.json file (normally the root directory) and will automatically "load" when babel-core is required to determine which preset(s) or plugins are to be used.
Inside .babelrc , you will need to add the following code :
{
"presets": ["es2015"]
}
3. pg-promise Testing Section
A direct quote from the developer recently answered this
You do not need to worry about steps in the Tests, use only the steps in the install. The one in tests relates to the dev dependency installation, in order to run tests. The pg-promise can work with any promise library compliant with Promises/A+ spec.
4. Standard File/Folder Structure for Server Side Projects?
There is no standard way to achieve this task as each project has unique demands. A good starting point would be to place the Entry file in the project root directory, the ES6 Config file in a "scripts" or "src" sub-folder and individual components in folders below that.
e.g.
ROOT/server.js
ROOT/src/config.es6
ROOT/src/component1/files.es6
ROOT/src/component2/files.es6
With this in place, Babel will successfully transpile all ES6 to ES5 and enable support of A+ compliant promises.
To begin using the node.js webserver This Guide provides a bit more insight and in the context of this answer the code shown would be placed into the ES6 config.es6 file and the following code would go into the Entry server.js file :
require("babel-core/register");
require("./src/config.es6");
The process for building Isomorphic web applications is different to this and would likely use things like grunt, gulp, webpack, babel-loader etc another example of which can be Found Here.
This answer is the combination of several key points provided by other answers to this question as well as contributions from experienced developers and my own personal research and testing. Thank you to all who assisted in the production of this answer.
This answer uses this simple directory structure
project/server/src/index.js => your server file
project/server/dist/ => where babel will put your transpiled file
Install babel dependencies
npm install -g babel nodemon
npm install --save-dev babel-core babel-preset-es2015
Add these npm scripts to your package.json file
"scripts": {
"compile": "babel server/src --out-dir server/dist",
"server": "nodemon server/dist/index.js
}
Create a .babelrc file in your project root directory
{
"presets": "es2015"
}
Transpile your directory with
npm run compile
Run your server with
npm run server
I think you should use a tool like grunt or gulp to manage all your "build" tasks. It will automate it for you, and you won't make errors.
In one command, you can transpile your code into babel ES2015 et start your application.
I suggest you to take a look at this simple project. (just install node_modules and launch npm start to start the app.js file)
However, if you really want to use babel manually,
.babelrc is the name of the file, you can see one in this project (redux) to have an example
.babelrc is a config file, if you want to see how it works, you can check this package.json (always redux)
There's actually no standard way that I know. You can use the project skeleton below if needed, and send pull request to improve it :-)
#makeitsimple
Step: 1
npm install nodemon --save
In project directory
Step: 2
yarn add babel-cli
yarn add babel-preset-es2015
Step: 2
In package.json-> scipts change 'start' to the following
start: "nodemon src/server.js --exec babel-node --presets es2015"
Step: 3
yarn start

Standard way of developing a node module using Coffeescript?

Is there a recommended way of developing a node module if I want to write it in Coffeescript, but don't want to force the module's users to require the coffee-script module?
Put your CoffeeScript codes in the src folder and the compiled JavaScript codes in lib folder.
Then in your package.json file, declare main to be the js file in the lib folder. Then the users of your package will require the js file instead of the coffee file.
You may take #TrevorBurnham's repository as an example.
I ended with only a src folder on my git repository; a .gitignore file with an line for lib; and an empty .npmignore file. The empty .npmignore file is needed because if it's not on your module, your .gitignore is used instead.
I just added a Cakefile with a task to build my src directory using coffee --compile --output lib/ src/ and a pretest and prepublish task to package.json to build before testing and publishing.
"scripts": {
"pretest": "cake build",
"prepublish": "cake build",
}
This solution keeps my git repository clean (without compiled code), but adds my javascript code to lib when publishing to npm.
I'm just getting started with CoffeeScript, but I'd suggest the following:
Store your CoffeeScript code in src/*.coffee,
Write a main.js in the project's root that NPM will catch, and have it simply do something like require('coffee-script'); require('./src/my_lib.coffee').
There. You never, ever compile your code; it's all handled transparently. You don't check compiled code into git, nor do you publish superfluous compiled JavaScript alongside the uncompiled CoffeeScript to NPM.
Edit:
In more recent versions coffee-scirpt, you should require('coffee-script/register');

Resources