I have a Typescript project:
myproject
|
+-src (folder)
| |
| +-main.ts
| +-stringHandler.ts
| +-disposable.ts
+-out (folder)
| |
| +-...
+-Gruntfile.js
In my Grunt configuration I have a 2-step task which compiles all .ts files in myproject/src/ and generates corresponding .js files into myproject/out/. So after the first step of the task is complete, I have the following:
myproject
|
+-out (folder)
|
+-main.js
+-stringHandler.js
+-disposable.js
Bundling
The second step of the task is generating bundle file myproject.js. I am using RequireJS for this purpose.
I have installed grunt-contrib-requirejs. The Gruntfile.js file handling the bundling task is as follows (showing only relevant parts in the file):
module.exports = function(grunt) {
var config = {
pkg: grunt.file.readJSON('package.json'),
requirejs: {
compile: {
options: {
baseUrl: "out",
bundles: {
'myproject': ['main', 'stringHandler', 'disposable']
},
out: 'out/myproject.js'
}
}
}
};
grunt.initConfig(config);
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.registerTask('default', ['compile', 'requirejs']);
};
When Grunt reaches requirejs, after successfully compiling the project, I get the following error:
Running "requirejs:compile" (requirejs) task { [Error: Error: Missing
either a "name", "include" or "modules" option
at Function.build.createConfig (C:\Users\myuser\Documents\myproject\node_modules\grunt-contrib-requirejs\node_modules\requirejs\bin\r.js:29567:19)
] originalError: [Error: Missing either a "name", "include" or
"modules" option] }
I can understand there are missing parameters, but when I use name I get other errors. I guess there must be something wrong at a more generic level. What is the correct configuration format? Thanks
This assumes main.ts is your application's entry point and that it contains a require.config section with your application dependencies (libraries and shims).
First, move the require.config section out of main.ts and into its own file, config.ts. Leave the application bootstrap code in main.ts.
Then determine where you want this optimized application code deployed. Let's assume it is to a directory named build, which is parallel to your src and out folders.
Update you Gruntfile to reflect this configuration:
requirejs: {
compile: {
options: {
baseUrl: "out",
mainConfigFile: "out/config.js",
modules: [
{ name: "main" }
],
dir: "build",
optimize: "none" // skip compression while debugging
}
}
}
You can read more about each of these config options at http://requirejs.org/ but here's the basic rundown:
baseUrl: Where the source JS code lives.
mainConfigFile: Points to the config object mentioned above. It tells the plugin where the dependencies live. This obviates the need to specify and manually update the list of dependencies in two places.
modules: Is an array of application bootstraps. In this case a list of one, main.js.
dir: Where the optimized application will be generated. Note that your dependencies will also be copied here.
optimize: I left this off so you can easily debug the resulting app under ./build. Remove it when you're happy and the plugin will optimize (compress and munge) your build files.
Related
im about to write a complex Incoming WebHook for Rocket.Chat. To avoid a mess in one single file i took Typescript. Rocket.Chat requires a class named Script with some predefined methods like process_incoming_request (one simple example: https://rocket.chat/docs/administrator-guides/integrations/).
my current project setup looks like:
tsconfig.ts
{
"files": [
"src/main.ts"
],
"compilerOptions": {
"noImplicitAny": true,
"target": "es2015"
}
}
gulpfile.js
var gulp = require("gulp");
var browserify = require("browserify");
var source = require("vinyl-source-stream");
var tsify = require("tsify");
var uglify = require("gulp-uglify");
var buffer = require("vinyl-buffer");
gulp.task(
"default",
function () {
return browserify({
basedir: ".",
debug: true,
entries: ["src/main.ts"],
cache: {},
packageCache: {}
})
.plugin(tsify)
.transform("babelify", {
presets: ["es2015"],
extensions: [".ts"]
})
.bundle()
.pipe(source("bundle.js"))
.pipe(buffer())
.pipe(uglify())
.pipe(gulp.dest("dist"));
}
);
main.ts
import {RequestInterface} from "./Interface/RequestInterface";
class Script {
process_incoming_request(request: RequestInterface) {
// some code
}
}
The yarn gulp process runs smoothly without errors but when using the generated code inside the script part of the webhook it results in an error:
Incoming WebHook.error script.js:1
ReferenceError: module is not defined
at script.js:1:4307
at Script.runInContext (vm.js:127:20)
at Script.runInNewContext (vm.js:133:17)
at getIntegrationScript (app/integrations/server/api/api.js:70:12)
at Object.executeIntegrationRest (app/integrations/server/api/api.js:166:13)
at app/api/server/api.js:343:82
at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1234:12)
at Object._internalRouteActionHandler [as action] (app/api/server/api.js:343:39)
at Route.share.Route.Route._callEndpoint (packages/nimble_restivus/lib/route.coffee:150:32)
at packages/nimble_restivus/lib/route.coffee:59:33
Im not that familiar with Typescript, Node and all the stuff. So the main question is, how can i achive that the process generates a class (or a script which exposes a class) named Script with the method process_incoming_request. Im also not sure if my script generates the error or the RocketChat part.
Thanks!
I guess the problem is that Gulp (or some of it's plugins) generates a scaffolding code, necessary for JS's (non-existent) module system, and it often implies wrapping the compiler output into weird multi-layered anonymous functions.
If you don't need any kind of module system and just want your multiple TS files translated directly to a single JS file (which supposedly goes to the RocketChat), then I'd suggest ditching Gulp altogether, letting TSC to compile your code as usual, then bundling the resulting .js files into a single one with a script.
So, the overall setup would be as follows (assuming src is a source code folder):
tsconfig.json
{
"include": [
"src/**/*.ts"
],
"compilerOptions": {
"noImplicitAny": true,
"target": "es2016"
}
}
build.sh
#!/bin/bash
# TSC puts compiled JS files along with their TS sources.
node_modules/typescript/bin/tsc
# Creating an empty bundle file.
echo "">dist/app.js
# Bundling all the JS together.
# sed removes the 'export' keywords & 'import' statements.
while read p; do
cat $p | sed -E "s/^export\s+(class|function|async|const|var)/\1/" | sed -E "s/import.*$//" >> dist/app.js
done <<< $(find src -type f -name "*.js")
So you program your thing as usual, build it with ./build.sh, get the dist/app.js file and use it in RocketChat.
There must be a way to do something along these lines in Gulp, but I'm not familiar with it, and don't think a full-blown build system is really needed here.
[UPDATE]
The original title of this post was : "Bad karma, lost data" and standed for the mind word play, much more for the rimes than for a real fact. So I decided to alter it, for the sake of correctness and courtesy.
[UPDATE]
Hi there, I've a very classical program directory strcture:
dist/
karam.conf.js
node_modules/
package.json
rollup.config.js
src/
fp/
list.js # imports maybe.js
matbe.js
test/
fp/
list.specs.js
maybe.specs.js
I'm trying to preprocess the tests with rollup. My karma.conf.js is just like :
# karma.conf.js
const buble = require('#rollup/plugin-buble')
const resolve = require('#rollup/plugin-node-resolve').default
// console.log({ resolve })
module.exports = function(config) {
config.set({
basePath : '',
files: [
{
pattern: 'src/fp/*.js', watched: true
},{
pattern: 'test/fp/*.specs.js', watched: true
}
],
watch: true,
preprocessors: {
'src/fp/*.js': ['rollup2'],
'test/fp/*.specs.js': ['rollup2']
},
rollup2Preprocessor: {
output: {
name: 'fptest',
format: 'iife'
},
plugins: [
buble(),
resolve()
]
}
});
}
When I start karma, with npm or from CLI with "karma start --log-level debug", I get 4 empty bundles and get the error message "Error during file loading or preprocessing
TypeError: output is not iterable".
So I could not test my program properly.
What's happening and how to fix that ?
Thanks for replies, Regards.
Looking at your module loader, I suggest using a karma plugin like karma-rollup-preprocessor to bundle your module before running tests. This will bundle and wire-up your modules properly for testing.
And you don't need to specify all your files under files array.
files: [
'test/**/*.js'
],
I'm using Lee Munroe's grunt-email-workflow to build out a set of email templates but I am not able to find where are the tasks configured.
When I run "grunt" from the terminal I can see that few tasks are executed:
-clean
-sass
-assemble pages
-juice
etc.
But the Gruntfile.js does not contain anything a part from:
module.exports = function(grunt) {
require('load-grunt-config')(grunt, {
// Pass data to tasks
data: {
// Re-usable filesystem path variables
paths: {
src: 'src',
src_img: 'src/img',
dist: 'dist',
dist_img: 'dist/img',
preview: 'preview'
},
// secrets.json is ignored in git because it contains sensitive data
// See the README for configuration settings
secrets: grunt.file.readJSON('secrets.json')
}
});
};
Am I missing something?
load-grunt-config is auto-loading the required grunt modules located in the package.json of the project. This is where clean (grunt-contrib-clean) sass (grunt-sass) etc are coming from.
This File determines which tasks are run by grunt
I have just developed a simple MEAN.JS application. MEAN.JS provides a command grunt build that helps me to minify the js and css files located at the following folders
css: [
'public/modules/**/css/*.css'
],
js: [
'public/config.js',
'public/application.js',
'public/modules/*/*.js',
'public/modules/*/*[!tests]*/*.js'
]
but how about also minifies the third-party libraries, which is installed with bower and located in public/lib/...? All the needed js and css file paths are already inside the MEAN.JS environment config file.
Meanwhile, the minified js file application.min.js is really just "minified", not "uglified", the variables' names are still the same as the original and very long.
In short, has MEAN.JS already provided any ways or functions that can "uglified" all the js and css files including third-party libraries?
EDIT:
To avoid errors when uglifying 3rd party files, only include non-minified 3rd party .js files in your config/env/all.js file.
Currently, your grunt build task uglifies your application javascript files but not your 3rd party javascript files. It does this via the uglify task in your grunt.js file.
uglify: {
production: {
options: {
mangle: false
},
files: {
'public/dist/application.min.js': 'public/dist/application.js'
}
}
},
If you want to uglify your 3rd party files I suggest taking the following steps:
Add your vendor files to your grunt.js file and the uglify task:
Change the configuration object (around line 170) to include your vendor files:
// A Task for loading the configuration object
grunt.task.registerTask('loadConfig', 'Task that loads the config into a grunt option.', function() {
var init = require('./config/init')();
var config = require('./config/config');
// insert vendor files
grunt.config.set("vendorJavaScriptFiles", config.assets.lib.js);
// note: you can do the same for your css files
grunt.config.set("vendorCSSFiles", config.assets.lib.css);
grunt.config.set('applicationJavaScriptFiles', config.assets.js);
grunt.config.set('applicationCSSFiles', config.assets.css);
});
Add your vendorJavaScriptFiles to your uglify task:
uglify: {
production: {
options: {
mangle: false
},
files: {
'public/dist/application.min.js': 'public/dist/application.js',
'public/dist/vendor.min.js': '<%= vendorJavaScriptFiles %>'
}
}
}
Change your config/env/production.js file to reflect your new vendor.min file:
assets: {
lib: {
css: [
'public/lib/bootstrap/dist/css/bootstrap.min.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
// note you can follow a similar process for your css files
],
js: 'public/dist/vendor.min.js'
},
css: 'public/dist/application.min.css',
js: 'public/dist/application.min.js'
}
Now, when you run grunt build you should get both an applicaiton.min.js file and a vendor.min.js file in your public/dist/ folder.
I separated them out for clarity, but you could combine them into one application.min.js file if you prefer.
Here is a much more detailed description of the process: https://blog.dylants.com/2014/11/19/bundling-production-assets-for-mean-js/
Hope this helps.
I'm having issues getting Grunt to perform requirejs optimization on a project with the following structure:
static/js
|── apps
|── app.js
|── dash.js
|── news.js
... (many more 'app' files)
|── build
|── collections
|── libs
|── models
|── util
|── views
Each of static/js/apps/*.js should be compiled to static/js/build/*.js containing the relevant dependencies (eg. views/view1, libs/query etc).
This is currently being performed by a basic bash script:
JS_ROOT="static/js"
for f in ${JS_ROOT}/apps/*
do
FILE=$(basename -s .js ${f})
pushd .
cd ${JS_ROOT} && r.js -o baseUrl=. name=libs/require-min.js include=apps/${FILE} out=build/${FILE}.js
popd
done
I'm attempting to move to a Grunt-based optimization, with the following in Grunt.js:
requirejs: {
compile: {
options: {
appDir: 'static/js/',
baseUrl: './apps/',
dir: 'static/js/build/',
modules: [
{
name: 'app',
}
]
}
}
}
Running generates the following error:
>> Tracing dependencies for: app
>> Error: ENOENT, no such file or directory
>> 'static/js/build/apps/libs/jquery.js'
>> In module tree:
>> app
I can clearly see what the problem is, but am failing to figure out how to indicate that the dependencies in each static/js/apps/*.js file are in static/js/ not static/js/build
In addition to this, I'm assuming that the modules block containing name: 'app' should be outputting the compiled file static/js/build/app.js from the contents of static/js/apps/app.js.
Without creating an additional module block for each file in static/js/apps, how can I compile each of the files into their relevant static/js/build/*.js file?
Update 1
So the following in my Gruntfile compiles static/js/apps/app.js successfully into static/js/build/app.js:
requirejs: {
compile: {
options: {
baseUrl: 'static/js/',
include: './apps/app.js',
out: 'static/js/build/app.js',
}
}
}
The next step being to compile static/js/apps/*.js into static/js/build/*.js without having to define each individually...
Update 2
Modifying the above to:
requirejs: {
compile: {
options: {
baseUrl: '../',
include: './apps/<%= appFile %>',
out: 'static/js/build/<%= appFile %>',
}
}
}
And creating the task:
grunt.registerTask('buildrjs', function() {
var dir='static/js/apps/';
grunt.file.setBase(dir);
var files = grunt.file.expand(['*.js']);
files.forEach(function(filename) {
grunt.log.write('Compiling '+filename+'\n');
grunt.config.set('appFile', filename);
grunt.task.run('requirejs:compile');
});
});
Almost gets me to the solution. The tasks runs through each file in static/js/apps/ and passes the filename into grunt.config.set('appFile', filename);. The output of the task outputs Compiling app.js Compiling news.js... etc, however afterwards the actual requirejs:compile tasks runs over & over on the last file in the static/js/apps/ directory, rather than each individual file. An async issue?
Solved, by passing multiple sets of options to the requirejs task, thanks to this article for the final pointers I needed:
module.exports = function(grunt) {
var files = grunt.file.expand('static/js/apps/*.js');
var requirejsOptions = {};
files.forEach(function(file) {
var filename = file.split('/').pop();
requirejsOptions[filename] = {
options: {
baseUrl: 'static/js/',
include: './apps/'+filename,
out: 'static/js/build/'+filename
}
};
});
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
requirejs: requirejsOptions,
});
};
Then the ['requirejs'] task can be run as normal and will output the appropriate compiled .js file as per each of the options: {} blocks that were specified in requirejsOptions, eg:
grunt.registerTask('default', ['requirejs']);
You need to change baseUrl to static/js from apps in requirejs build config. As currently baseUrl is pointing to apps directory, require is trying to search dependency files in apps directory. If you change the baseUrl to static/js it will find those dependency files.
requirejs: {
compile: {
options: {
appDir: 'static/js/',
baseUrl: 'static/js',
dir: 'static/js/build/',
modules: [
{
name: 'app',
}
]
}
}
}