@corprio/gulp-typescript
v1.0.7
Published
Gulp tasks to transpile typescript and add declarations for Corprio built-in web applications using Asp.Net Core MVC framework
Downloads
3
Readme
About the package @corprio/gulp-typescript
https://www.npmjs.com/package/@corprio/gulp-typescript
This package is created for projects built in the ASP.NET Core MVC framework and desires to use typescript for each of its views. It intends to solve the problems:
- Not getting intellisense or checkings for scripting in
.cshtml
views - If using separate script files, difficult to pass data from view to model
- If using ES modules, the code inside becomes scoped and cannot access it from outside elsewhere in the view
- If using ES modules, it may be bulky to serve all imported modules with the script
What it can do
Transpiles typescript
It will transpile each of your typescript files found in the Views
folder
into javascript files and outputs that into the wwwroot/js/views
folder,
under the same folder structure.
Project folder
+-- wwwroot
| +-- js
| +-- views
| +-- Foo
| +-- Bar.js //this javascript will be outputted
+-- Controllers
+-- Models
+-- Views
| +-- Foo
| +-- Bar.cshtml
| +-- Bar.ts //this typescript file will transpile
It will also watch for changes in the typescript files to re-transpile.
Declares typing for javascript data model object in defined in view
Suppose you have a typescript file Bar.ts
that is used in your view Bar.cshtml
.
How can you access the view model? You can no longer use @Model.MyProperty
because you are not in the view file but in the script file.
What you might do is to define an object in your view like this.
<script type="text/javascript">
var vdata = {
myProperty = '@Model.MyProperty'
};
</script>
Then in your script, you reference it.
doSomething(vdata.myProperty);
However, if you're using typescript, you'll an error Cannot find name: 'vdata'
,
because vdata is not defined in the script. So you'll have to declare it first by adding
declare const vdata: any;
but when doing so, you will get no hint as to the shape of this vdata
object.
So this package offers the solution by searching through the view and finding
a definition of the vdata
object, and then declares its shape into your
typescript file. In the case above, it will automatically declare it at the top of
your script, adding the following lines:
declare const vdata: {
myProperty: string
}
It will also watch for changes in the view to re-declare.
Expose the javascript to global access
Suppose you use the import
statement in your script to make use of third-party libraries,
or to reuse code from your own modules. Your script is now a module because it contains
either the import
or the export
statement.
So to include the script in the view you must add type="module"
<script type="module" src="~/js/views/Foo/Bar.js"></script>
And that is fine if all your scripting is done in that Bar.js
, which is generally
a good idea. But suppose you must access a function from Bar.js
in your view.
In the case of many Corprio apps, we make use of the DevExtreme library for ASP.NET Core MVC, which allows us to write in C# that will in turn transpile into javascript for us later at run-time. Let's say you have something like this in your view:
@Html.DevExtreme().TextBoxFor(m => m.MyProperty).OnInitialized("initTextBox")
Here, you want to access initTextBox
function from the view, which you have
previously defined in your script. But your script is a module and so it is scoped and not
accessible globally.
import * as anotherModule from './anotherModule.js' //this will hence make it a module
//cannot access this function globally
function initTextBox(e){
...
}
How this package solves the problem is it will wrap the script inside a UMD module
under a namespace, say vjs
. That way you can expose the initTextBox
function by exporting it.
export function initTextBox(e){
...
}
Then in your view, access it under the vjs
namespace.
@Html.DevExtreme().TextBoxFor(m => m.MyProperty).OnInitialized("vjs.initTextBox")
Treeshaking
Suppose you import something in your script.
import * as anotherModule from './anotherModule.js'
function initTextBox(e){
anotherModule.addEffect(e);
}
You script now imports anotherModule
and it will be included in the output.
But anotherModule
might be a large module with many functions, and you are only
using one of it.
This packages solves this by treeshaking it with webpack, so that only what is used will be included. And whatever is not used will not be bundled together.
How to use
1. Install the package
Run this command in the root of your project where the package.json
is.
npm install @corprio/gulp-typescript --save-dev
2. Create a tsconfig.json
Add a configuration file for typescript in the root of your project, with the following content.
{
"compilerOptions": {
"forceConsistentCasingInFileNames": true,
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es6",
"module": "esnext",
"moduleResolution": "nodenext",
//if using corprio.js
"types": [ "jquery", "file-saver", "bootstrap", "node" ]
},
"include": [
"Views/**/*",
//if using corprio.js
"node_modules/@corprio/aspnetcore-site/dist/js/**/*"
]
}
This file is important because this package's gulp tasks will transpile
the typescript based on settings in the tsconfig.json
.
A brief explanation of what those configs do:
The include
configures which files the compiler should include.
Here, Views/**/*
told it to include all the typescript files from the Views
folder, because those are the files we need to transpile to javascript.
If you're using corprio.js
from the @corprio/aspnetcore-site
package,
You should also include node_modules/@corprio/aspnetcore-site/dist/js/**/*
so that the declaration files for corprio.js
will be included.
This will also include .d.ts
files for DevExtreme because corprio.js
uses it.
The types
configures which typings it should include from node_modules/@types
.
For example, if you're using jquery
then you should include that here, given you
have already installed the @types/jquery
package.
Here, we are including jquery
, file-saver
,
bootstrap
, node
because corprio.js
uses them.
The module
is set to esnext
so that dynamic imports are supported.
The target
is set to es6
, which the gulp tasks from this package
will use to further treeshake and bundle.
As for the other settings, you can see what they do in https://www.typescriptlang.org/tsconfig.
3. Set TypeScriptCompileBlocked to true
Add the following lines to your .csproj
project file.
<PropertyGroup>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup>
This will tell Visual Studio to not run typescript compile on MSBuild. We will take care of that with gulp instead.
4. Install gulp
You will need gulp to run the tasks that are included in this package. Go ahead and install gulp as well.
npm install gulp --save-dev
5. Create a gulpfile.js
Create a gulpfile.js
in the root of your project.
Add the following content inside.
const gulpTs = require('@corprio/gulp-typescript');
//deletes everything inside wwwroot/js/views folder
exports.cleanJsViews = gulpTs.cleanJsViews;
//process typescript files to transpile to js files, and add declarations to ts from view
//then keep watching for changes
exports.processTs = gulpTs.processTs;
//cleans www/js/views and repopulate with transpiled js, refresh declarations in ts,
//keeps watching for changes in views and ts to update
exports.refreshAll = gulpTs.refreshAll;
//watch for changes in typescript files and their views to transpile or generate declaration on demand
exports.watchTsAndViews = gulpTs.watchTsAndViews;
The gulpfile.js
contains tasks that can be run to perform pipeline processes for
your client-side resources. Here we have imported our package into the gulpTs
variable. Then we retrieved four different tasks from the package and exported them.
When we export a task, we make it available for us to run via the
Task Runner Explorer.
6. Run the processTs task
Open Task Runner Explorer from Visual Studio
found under View > Other Windows > Task Runner Explorer.
You will now see the four exported tasks from our gulpfile.js
.
Right-click processTs
and hit Run.
The processTs
task will generate the javascript files for you
under wwwroot/js/views
. It will also add declarations of vdata
into your
typescript files. Then it will keep watching for changes and redo that accordingly.
7. Watch for change on project open
Now that you have everything generated, you won't need to keep right-clicking and running the task every time. You just have to tell gulp to keep watching for changes every time the project opens.
To do so, open the Task Runner Explorer panel, right-click on watchTsAndViews
and click Bindings, select Project Open.
This will actually add the following line to the top of your gulpfile:
/// <binding ProjectOpened='watchTsAndViews' />
So now every time you open the project, this watchTsAndViews
task will run,
and keep watching and processing as you go.
Documentation
initConfig(config: InitOptions)
Initialize configurations to override the defaults.
Just run the function from your gulpfile.js
, before any other tasks are executed.
If the defaults works fine for you, just don't run this function.
const gulpTs = require('@corprio/gulp-typescript');
gulpTs.initConfig({
jsModuleNamespace: 'vjs',
viewDataObjName: 'vdata',
srcPath: 'Views/**/*.ts'
destPath: 'wwwroot/js/views/'
});
InitOptions
jsModuleNamespace: string
Default value: 'vjs'
Namespace for the output js UMD modules. This exposes it globally so the view can access any exported functions from the script.
viewDataObjName: string
Default value: 'vdata'
Name of the js object which is defined in the view that you wish to make known to the script file. A typescript declaration will be generated in the script file for that object.
srcPath: string | string []
Default value: 'Views/**/*.ts'
The glob pattern(s) that points to the typescript files that you wish to process.
destPath: string
Default value: 'wwwroot/js/views/'
The file path to the destination folder where you wish the javascript files to be outputted.
cleanJsViews()
A gulp task that deletes all files from destPath
(default: 'wwwroot/js/views').
Use with caution as it erases everything from the folder.
Make sure to run transpileAll()
again after this action to regenerate the javascript files.
processTs_PRODUCTION()
A gulp task that processes typescript files to transpile to javascript files,
and adds type declarations to typescript files of the viewDataObjName
(default: 'vdata')
object as defined in the view.
Then keeps watching for changes to transpile or declare on demand.
Basically, it runs
gulp.parallel(
gulp.series(declareAll, transpileAll),
watchDeclare
)
It will transpile to both minified and non-minified scripts.
processTs_DEVELOPMENT()
Same as processTs_PRODUCTION()
but It will only transpile to
non-minified scripts.
refreshAll_PRODUCTION()
A gulp task that cleans the output folder and regenerates, then keeps watching.
Basically, it runs
gulp.series(
cleanJsViews, processTs
)
It will transpile to both minified and non-minified scripts.
refreshAll_DEVELOPMENT()
Same as refreshAll_PRODUCTION()
but It will only transpile to
non-minified scripts.
watchTsAndViews_PRODUCTION()
A gulp task that watches each typescript file for change.
On change, it will transpile the javascript for that file.
It also watches each .cshtml
file that has an associated typescript file
(Bar.cshtml
and Bar.ts
are associated because they share the same file name).
On change, it will declare the type declaration for viewDataObjName
(default: 'vdata') in the typescript file.
It will transpile to both minified and non-minified scripts.
watchTsAndViews_DEVELOPMENT()
Same as watchTsAndViews_PRODUCTION()
but It will only transpile to
non-minified scripts.
transpileAllJs()
A gulp task that transpiles each typescript files that matches the pattern in srcPath
(default: 'Views/**/*.ts') into javascript UMD modules, under the namespace
jsModuleNamespace: string
(default: 'vjs'). It will keep the same folder structure
and file name as the source.
For example, these typescript files:
+-- Views
| +-- Fruits
| +-- Apple.cshtml
| +-- Apple.ts
| +-- Orange.cshtml
| +-- Orange.ts
| +-- Veggies
| +-- Lettuce.cshtml
| +-- Lettuce.ts
Will output the following folders and javascript files.
Project folder
+-- wwwroot
| +-- js
| +-- views
| +-- Fruits
| +-- Apple.js
| +-- Orange.js
| +-- Veggies
| +-- Lettuce.js
Any imports made in the typescript file, will be bundled into the javascript file, after treeshaking. Note: this is only possible if the imports are of ES modules.
transpileAllMinJs()
Same as transpileAllJs()
but transpiles to minified scripts.
declareAll()
A gulp task that adds type declarations to typescript files of the
viewDataObjName
(default: 'vdata') object as defined in the associated view.
You may have this in your view Apple.cshtml
<script type="text/javascript">
var vdata = {
model: {
color = '@Model.Color',
fridgeLife = number('@Model.FridgeLife'),
isSoldOut = '@Model.IsSoldOut' == 'true',
},
link = '@Url.Action("Apple", "Fruits")'
};
</script>
This will add the following to the top of Apple.ts
declare const vdata: {
model: {
color: string;
fridgeLife: number;
isSoldOut: boolean;
};
link: string;
}
watchDeclare()
A gulp task that watches each .cshtml
file that has an associated typescript file
(Bar.cshtml
and Bar.ts
are associated because they share the same file name).
On change, it will declare the type declaration for viewDataObjName
(default: 'vdata') in the typescript file.