I have modular javascript application and I need to have js frameworks in one file "global-libs.js", which dependencies will be accessible for every file using webpack. Other js files will only use these dependencies but it will not be part of the final bundle. I'am using Gulp for these task in combination of Webpack.
This is task for webpack and transpile my jsx into js where should be only my code, not external libraries
gulp.task('js',['jsx'], function () {
/**This dependency is external, its not part of the bundle */
return gulp.src(config.paths.workDir + config.paths.jsPath + '/**/*.js')
.pipe(webpack({
externals: {
"react": "React"
}
}))
.pipe(rename('onlyCustomJs.js'))
.pipe(gulpif(args.production, uglify()))
.pipe(gulp.dest(config.paths.portlets.newNotePortlet + config.paths.jsPath))
});
This task should create files only with externals libraries and dependency React should be accessible using require in every js webpack file.
gulp.task('global', function(){
/**This will be accessible globally*/
return gulp.src(config.paths.srcDir + config.paths.jsPath + '/global-libs.js')
.pipe(webpack({
output: {
libraryTarget: "var",
library: "React"
}
}))
.pipe(rename('global-libs.js'))
.pipe(gulp.dest(config.paths.portlets.evremTheme + config.paths.jsPath))
});
This file uses global react dependency. But it tells me that React is undefined at var HelloMessage = React..
/** #jsx React.DOM */
var React = require('react');
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.renderComponent(HelloMessage({name: "Hello world"}), document.getElementById('example'));
This is global-libs.js file
var React = require('react');
var jQuery = require('jquery');
Thank you!
Maybe It's not to best solution but I solved by these changes.
//These is dependencies which will be bundled in one global-libs.js file and will be accessible from everywhere through require().
module.exports = React = require('react');
module.exports = jQuery = require('jquery');
Webpack only merge these two files and publish them through module.exports
gulp.task('global', function(){
/**This will be accessible globally*/
return gulp.src(config.paths.srcDir + config.paths.jsPath + '/global-libs.js')
.pipe(webpack())
.pipe(rename('global-libs.js'))
.pipe(gulp.dest(config.paths.destDir + config.paths.jsPath))
});
My gulp task for bundling my conde is like this. Only specified externals dependencies which will not be part of the bundle.
gulp.task('js',['jsx'], function () {
/**This dependency is external, its not part of the bundle */
return gulp.src(config.paths.workDir + config.paths.jsPath + '/**/*.js')
.pipe(webpack({
externals: {
"react": "React",
"jquery": "jQuery"
}
}))
.pipe(rename('bundle.js'))
.pipe(gulpif(args.production, uglify()))
.pipe(gulp.dest(config.paths.destDir + config.paths.jsPath))
});
In result I can import dependencies like this.
/** #jsx React.DOM */
var React = require('react');
var jQuery = require('jquery');
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
React.renderComponent(HelloMessage({name: "Hello world"}), jQuery('#example')[0]);
Related
I created a simple app using knockout/bootstrap/gulp that downloads a pdf using pdfMake.js. It works fine in debug mode using VS2017. After publishing and using gulp it gives this error when run: File 'Roboto-Regular.ttf' not found in virtual file system
Note: After gulp, all JS files are in one script.js file.
I tried many things, it always works when debugging, as soon as I run gulp, it gives the error.
I tried joepal1976's solution from here (what I did with the dependencies in require.config.js)
Someone suggested .pipe(uglify({
compress: {
hoist_funs: false
}
})) which doesn't appear to help.
Included in require.config like so:
var require = {
baseUrl: ".",
paths: {
"jquery": "js-libs/jquery.min",
"bootstrap": "js-libs/bootstrap.min",
"crossroads": "js-libs/crossroads.min",
"hasher": "js-libs/hasher.min",
"knockout": "js-libs/knockout",
"knockout-projections": "js-libs/knockout-projections.min",
"signals": "js-libs/signals.min",
"text": "js-libs/text",
"vfs_fonts": "js-libs/vfs_fonts",
"pdfMake": "js-libs/pdfmake.min"
},
shim: {
"bootstrap": { deps: ["jquery"] },
'pdfMake':
{
exports: 'vfs_fonts'
},
'vfs_fonts':
{
deps: ['pdfMake'],
exports: 'vfs_fonts'
}
}
};
JS for the page:
define(["knockout", "text!./home.html"], function (ko, homeTemplate) {
function HomeViewModel(route) {
var thisVM = this;
this.VMInit = function () {
var thePDF = {
content: [
'My test invoice.',
]
};
pdfMake.createPdf(thePDF).download('pdf_test.pdf');
}
thisVM.VMInit();
}
return { viewModel: HomeViewModel, template: homeTemplate };
});
The Gulp file:
//-----------------------------------------------------------------------
// Node modules
var fs = require('fs'),
vm = require('vm'),
merge = require('deeply'),
chalk = require('chalk'),
es = require('event-stream');
//-----------------------------------------------------------------------
// Gulp and plugins
var gulp = require('gulp'),
rjs = require('gulp-requirejs-bundler'),
concat = require('gulp-concat'),
clean = require('gulp-clean'),
replace = require('gulp-replace'),
uglify = require('gulp-uglify'),
htmlreplace = require('gulp-html-replace');
// Config
var requireJsRuntimeConfig =
vm.runInNewContext(fs.readFileSync('src/app/require.config.js') + '; require;');
requireJsOptimizerConfig = merge(requireJsRuntimeConfig, {
out: 'scripts.js',
baseUrl: './src',
name: 'app/startup',
paths: {
requireLib: 'js-libs/require'
},
include: [
'requireLib',
'components/nav-bar/nav-bar',
'components/home-page/home',
'text!components/about-page/about.html'
],
insertRequire: ['app/startup'],
bundles: {
// If you want parts of the site to load on demand, remove them from the 'include' list
// above, and group them into bundles here.
// 'bundle-name': [ 'some/module', 'another/module' ],
// 'another-bundle-name': [ 'yet-another-module' ]
}
});
//-----------------------------------------------------------------------
// Discovers all AMD dependencies, concatenates together all required .js
files, minifies them
gulp.task('js', function () {
return rjs(requireJsOptimizerConfig)
.pipe(replace('Views/src/', ''))
.pipe(replace('img/', 'Assets/img/'))
.pipe(replace('css/', 'Assets/css/'))
.pipe(uglify({
preserveComments: 'some'
}))
.pipe(gulp.dest('./dist-app/Assets/js/'));
});
gulp.task('css', function () {
return gulp.src(['./src/css/bootstrap.css',
'./src/css/bootstrap-switch.css',
'./src/css/dataTables.bootstrap.css',
'./src/css/dataTables.colVis.css',
'./src/css/dataTables.responsive.css',
'./src/css/daterangePicker.css'])
.pipe(concat('styles.css'))
.pipe(gulp.dest('./dist-app/Assets/css/'));
});
// Copies index.html, replacing <script> and <link> tags to reference production
URLs
gulp.task('html', function () {
return gulp.src('./src/index.html')
.pipe(htmlreplace({
dependencies_top: '<link href="Assets/css/styles.css"
rel="stylesheet">',
dependencies_bottom: '<script src="Assets/js/scripts.js"></script>'
}))
.pipe(gulp.dest('./dist-app/'));
});
// Removes all files from ./dist/
gulp.task('clean', function () {
console.log("the clean task");
return gulp.src('./dist-app/**/*', { read: false })
.pipe(clean());
});
// All tasks in [] must complete before 'default' can begin
gulp.task('default', ['html', 'js', 'css'], function (callback) {
callback();
console.log('\nPlaced optimized files in ' + chalk.magenta('dist-app/\n'));
});
The Startup.js file if its helpful:
define(['jquery',
'knockout',
'./router',
'bootstrap',
'knockout-projections',
'pdfMake',
'vfs_fonts'], function ($, ko, router) {
// Components can be packaged as AMD modules, such as the following:
ko.components.register('nav-bar', { require: 'components/nav-bar/nav-bar' });
ko.components.register('home-page', { require: 'components/home-page/home'
});
// ... or for template-only components, you can just point to a .html file
directly:
ko.components.register('about-page', {
template: { require: 'text!components/about-page/about.html' }
});
ko.components.register('new-page', { require: 'components/new-page/new-page'
});
// [Scaffolded component registrations will be inserted here. To retain this
//feature, don't remove this comment.]
// Start the application
ko.applyBindings({ route: router.currentRoute });
});
Following code worked for me:
import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";
pdfMake.vfs = pdfFonts.pdfMake.vfs;
I battled with this recently on stackblitz when using it with angular. the issue was pdfmake.vfs on the window object was not being set. so i had to manually set it in the constructor of my pdf service like so.
constructor() {
(window as any).pdfMake.vfs = pdfFonts.pdfMake.vfs;
}
I came across this issue and resolved it by including vfs_fonts.js just after the pdfmake Javascript file.
Here is my code, you should just need to set the file path to wherever your copy of the file is placed.
<script src="~/Content/DataTables/pdfmake-0.1.32/pdfmake.min.js"></script>
<script src="~/Content/DataTables/pdfmake-0.1.32/vfs_fonts.js"></script>
CDN LINK
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.32/vfs_fonts.js"></script>
please follow the hierarchy/dependency of links else it won't work
It is just the sequence of the files, add first the pdfmake and then vfs_fonts.
#Rijo solution worked in one file, but oddly enough refused to work in another file.
In the other file I had to use:
import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";
// Wherever you call createPdf, you have to pass VFS
pdfMake.createPdf(docDefinition, null, null, pdfFonts.pdfMake.vfs).open();
I'm trying to build a js bundle from typescript with exports that I can call directly from an inline script, but I don't seem to be able to get it to work.
I have a Typescript source file like this:
export namespace Init {
export function index() {
// do some things
}
}
export function blahblah() { console.log('blahblah') }
This sits alongside some other sources in the same folder src/ts/*.ts. My webpack.config.js looks like this:
'use strict';
module.exports = {
context: __dirname,
output: {
filename: 'bundle.js',
library: 'bitthicket',
},
devtool: 'sourcemap',
resolve: {
extensions: [ '.ts', '.tsx', '.js' ]
},
module: {
rules: [
{ test: /\.tsx?$/, exclude: /node_modules/, loader: 'ts-loader' }
]
}
}
And finally, my gulpfile.js looks like this:
var gulp = require('gulp')
var gutil = require('gulp-util')
var plumber = require('gulp-plumber')
var watch = require('gulp-watch')
var sass = require('gulp-sass')
var ts = require('gulp-typescript')
var clean = require('gulp-clean')
var webpack = require('webpack')
var webpack_config = require('./webpack.config.js')
var webpack_stream = require('webpack-stream')
let _sass = () =>
gulp.src('src/css/**/*.scss')
.pipe(plumber())
.pipe(sass())
.pipe(gulp.dest('static/css'))
.on('end', () => gutil.log('_sass: done'))
let _webpack = () =>
gulp.src('src/ts/**/*.ts')
.pipe(plumber())
.pipe(webpack_stream(webpack_config, webpack))
.pipe(gulp.dest('static/js'))
.on('end', () => gutil.log('_webpack: done'))
gulp.task('build:sass', _sass)
gulp.task('clean:sass', () => gulp.src('static/css/**/*').pipe(clean()))
gulp.task('watch:sass', () => watch('src/css/**/*.scss', () => _sass()))
gulp.task('build:webpack', _webpack)
gulp.task('clean:ts', () => gulp.src('static/js/**/*').pipe(clean()))
gulp.task('watch:webpack', () => watch('src/ts/**/*.ts', () => _webpack()))
gulp.task('watch', ['watch:sass', 'watch:webpack'])
gulp.task('clean', ['clean:sass', 'clean:ts'])
gulp.task('build', ['build:sass', 'build:webpack'])
gulp.task('default', ['clean', 'build'])
In an html file:
<script src="bundle.js" async></script>
<script>window.onload = function() { console.log(bitthicket); }</script>
What's happening, as I understand it, is that webpack is getting the piped list of sources as entry files, as though they were placed on the commandline like webpack {src list} bundle.js. But I've set my library output option, and the bitthicket variable does get set, but it's an empty object. What happened to Init.index?
Edit: I added the export keyword to the Init namespace, as well as a plain function to init.ts to see what would happen - but the resulting object still doesn't have those functions.
Here's the resulting webpack bootstrapper argument:
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
exports.__esModule = true;
var _ = __webpack_require__(2);
var Init;
(function (Init) {
function index() {
Nav.attachNavbarScrollWatcher();
document.addEventListener('scroll', function (event) {
var articles = document.querySelectorAll('.featured column.summary article');
var visibleArticle = _.find(articles, function (el) { return Util.isElementInViewport(el); });
console.log("{0} just became visible", visibleArticle);
});
}
Init.index = index;
})(Init = exports.Init || (exports.Init = {}));
function blahblah() {
console.log('blahblah');
}
exports.blahblah = blahblah;
/***/ }),
As you can see, exports.blahblah and exports.Init.index are assigned in this block - but the object I get back in my browser looks like this:
The real answer to my question is
Do you even module, bro?
I just flat-out misunderstood the relationship between what typescript calls namespaces and modules, and what webpack thinks modules are.
After this exercise in futility, I'm not even sure what the point of Typescript namespaces are anymore, unless you have a multi-stage build process where you use tsc and tsconfig.json to create multiple transpiled bundles that will later be re-bundled by some other loader like Webpack.
Anyway, to the point:
Typescript "namespaces" mean nothing at all to Webpack (more specifically, ts-loader: see TypeStrong/ts-loader#193). Webpack is not able to walk namespace dependencies, and so you wind up with undefined symbols in the bundle, which means the webpackBootstrap function also had no idea how to load things in the right order. The entry point in my bundle was kinda like this:
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
__webpack_require__(1); // <-- actual entry point, exports are lost
__webpack_require__(2);
exports = __webpack_require__(4); // <-- not entry point, nothing is exported here anyway
/***/ }),
...
Webpack (and ts-loader) require a form of modules that it understands in order to make the bootstrapper load things correctly.
I'm still using a Typescript namespace for structure, but I'm exporting it and using import to indicate dependencies on other Typescript modules:
import * as _ from 'lodash'
import * as Nav from './nav'
import * as Util from './util'
export namespace Init {
// ...
}
The main thing is the expression of the dependencies as es2015-style import/exports.
I am working on a project where I am using gulp. However, gulp keeps throwing an error saying it cannot find the AppAPI.js file in my work environment. I am building with Reactjs and Flux. I believe the problem may be in my gulpfile, but after trying various versions of the code, I have not been able to get anywhere. Could someone take a look and see if indeed my code is wrong or if there could be something else going wrong? Here is my gulpfile:
var gulp = require('gulp');
var browserify = require('browserify');
var reactify = require('reactify'); // Converts jsx to js
var source = require('vinyl-source-stream'); // Converts string to a stream
gulp.task('browserify', function(){
browserify('./src/js/main.js')
.transform('reactify')
.bundle()
.pipe(source('main.js'))
.pipe(gulp.dest('dist/js'));
});
gulp.task('copy', function(){
gulp.src('src/index.html')
.pipe(gulp.dest('dist'));
gulp.src('src/css/*.*')
.pipe(gulp.dest('dist/css'));
gulp.src('src/js/vendors/*.*')
.pipe(gulp.dest('dist/js'));
});
gulp.task('default', ['browserify', 'copy'], function(){
return gulp.watch('src/**/*.*', ['browserify', 'copy']);
});
I am requiring appAPI.js in my main.js file:
var App = require('./components/App');
var React = require('react');
var ReactDOM = require('react-dom');
var AppAPI = require('./utils/appAPI.js');
ReactDOM.render(
<App />,
document.getElementById('app')
);
Here is the appAPI.js code:
var AppActions = require('../actions/AppActions');
module.exports = {
}
I'm trying to include 3-d party component as follows:
app.js
/** #jsx React.DOM */
var React = require('react'),
ReactDOM = require('react-dom');
Isvg = require('react-inlinesvg');
ReactDOM.render(
<Isvg src="images/mobile.svg" />,
document.getElementById('mobile')
);
package.json:
...
"browser": {
"react": "./node_modules/react/dist/react.js",
"react-dom": "./node_modules/react-dom/dist/react-dom.js",
"react-inlinesvg": "./bower_components/react-inlinesvg/standalone/react-inlinesvg.js",
"react-lazyload": "./node_modules/react-lazy-load/dist/LazyLoad.js"
},
"browserify": {
"transform": [
["reactify", {"es6": true}]
]
}
and finally gulp task configuration:
var gulp = require('gulp'),
config = require('../config')(),
utils = require('../utils'),
plugins = require('gulp-load-plugins')({lazy: true}),
browserify = require('browserify'),
source = require('vinyl-source-stream'),
reactify = require('reactify'),
watchify = require('watchify');
gulp.task('make-js', function() {
var options = {
debug: true,
entries: config.js,
transform: [reactify],
cache: {}, packageCache: {}, fullPaths: true
},
bundler = watchify(browserify(options));
bundler.on('update', rebundle);
function rebundle() {
utils.log('start bundling...');
bundler
.bundle()
.on('error', utils.handleErrors)
.pipe(source('bundle.js'))
.pipe(gulp.dest(config.tmp));
utils.log('finished bundling...');
}
return rebundle();
});
This creates bundle.js file without any problems however the 3-d party inlinesvg component does not work and produces the following error in the browser javascript console:
Uncaught TypeError: Cannot read property 'PropTypes' of undefined
The error is caused by the following code in react-inlinesvg.js
Line 566
PropTypes = React.PropTypes;
I'm pretty sure I've missed something important in the browserify configuration but cannot figure out what I did wrong exactly.
Thanks for your help.
It seems to be an issue with that 3-d party component. I'm newbie in react so in order to exclude my configuration errors I used 100% working boilerplate. But the issue remained. The investigation revealed the module itself does not import React in a proper way.
My original question could be actually split into 2 questions (how to include that module and how to load SVG files inline so let me answer the second part of my question).
I did not find any working modules which could load svg without any 3-d party modules like jquery or creating my own bicycle.
I came up with the well-known SVGInjector javascript module. It is a vanilla js module but has the necessary browserify support. I wrapped it into react component without problems. Here is the code:
class svg extends React.Component {
componentDidMount(){
return SVGInjector([ReactDOM.findDOMNode(this)]);
}
constructor(props) {
super(props);
}
render() {
return React.DOM.img({
className: this.props.className,
'data-src': this.props.path,
'data-fallback': this.props.fallbackPath});
}
}
I use CommonJS modules with require() except React, which is global:
// I don't want require React in every module:
// var React = require("react");
var MyComponent = React.createClass({ // React is global here
});
When running a unit test on MyComponent, Jest can't find React. Is there a way to tell Jest to insert a global React object? (I use npm and gulp-browserify.)
Works for me with the following settings.
// package.json
"jest": {
"scriptPreprocessor": "preprocessor.js",
"unmockedModulePathPatterns": [
"react"
],
"setupEnvScriptFile": "before_test.js"
}
// preprocessor.js
var ReactTools = require('react-tools');
module.exports = {
process: function(src) {
return ReactTools.transform(src);
}
};
// before_test.js
React = require("react"); // Global React object