I am using webpack to bundle/transform jsx.
From the command line I'm running "webpack --watch". This creates my bundle without errors. Here's my webpack config and Application.js
'use strict';
var webpack = require('webpack');
module.exports = {
resolve: {
extensions: ['', '.js']
},
devtool: 'eval',
entry: './client.js',
output: {
path: __dirname+'/build/js',
filename: 'client.js'
},
module: {
loaders: [
{ test: /\.css$/, loader: 'style!css' },
{ test: /\.js$/, loader: 'jsx-loader?harmony' }
]
}
};
var React = require('react'),
classSet = require('react/addons'),
Nav = require('./Nav.js'),
Home = require('./Home.js'),
Recipe = require('./Recipe.js'),
RecipeArchive = require('./RecipeArchive.js'),
About = require('./About.js'),
Timestamp = require('./Timestamp.js'),
RouterMixin = require('flux-router-component').RouterMixin;
var Application = React.createClass({
mixins: [RouterMixin],
getInitialState: function () {
this.store = this.props.context.getStore('ApplicationStore');
return this.store.getState();
},
componentDidMount: function () {
var self = this;
self._changeEventListener = function () {
var state = self.store.getState();
self.setState(state);
};
self.store.on('change', self._changeEventListener);
},
componentWillUnmount: function () {
var self = this;
self.store.removeListener('change', self._changeEventListener);
self._changeEventListener = null;
},
render: function () {
return (
<div>test</div>
);
}
});
module.exports = Application;
Then I'm running my node server which throws an error.
node server.js
results in:
/Users//Documents/routing/components/Application.js:39
<div>test</div>
^
SyntaxError: Unexpected token <
How should I be running my project to allow me to include jsx/harmony in my .js files?
UPDATE: Solution
As Brandon pointed out, I needed to use node-jsx for transforms in Node. At the top I've of my server.js file I've added and alls working:
require('node-jsx').install({ extension: '.js', harmony: true });
Webpack just creates a client-side bundle; when you run your Node app, it doesn't use webpack to load the files. Prevously you could use something like node-jsx to require JSX files in Node.js, but that project has since been deprecated in favor of Babel. In particular, you can use babel-register to require JSX files in Node.
Related
I have a an es6 JS class below which I am running through browserify to output in es5. Below is my es6 JS class:
import $j from "jquery";
import BaseComponent from './Components/base-component';
class QuestionnaireView extends BaseComponent {
constructor() {
super();
this.defaultOptions = {
questionId : '#questionId',
responseId : '#responseId',
answerId : '#answerId',
questionTextId : '#questionTextId'
};
this.state = {
};
}
initChildren() {
}
addListeners() {
}
collectQuestions() {
var questionAndAnswersDict = [];
var answersAndWeightingsDict = [];
$j(this.options.questionId).each(function () {
var questionText = $j(this).find("input")[0].value;
$j(this.options.answerId).each(function () {
var answerText = $j(this).find("input")[0].value;
var weighting = $j(this).find("input")[1].value;
answersAndWeightingsDict.push({
key: answerText,
value: weighting
});
});
questionAndAnswersDict.push({
key: questionText,
value: answersAndWeightingsDict
});
});
}
collectResponses() {
var responsesDict = [];
var weightingDict = [];
$j(this.options.responseId).each(function () {
var minWeighting = $j(this).find("input")[0].value;
var maxWeighting = $j(this).find("input")[1].value;
var responseText = $j(this).find("input")[2].value;
weightingDict.push({
key: minWeighting,
value: maxWeighting
});
responsesDict.push({
key: responseText,
value: weightingDict
});
});
}
}
export default () => { return new QuestionnaireView(); };
And here is the browserify command I am running:
browserify Scripts/questionnaire-view.js -o wwwroot/js/questionnaire-view.js
I have also tried
browserify Scripts/questionnaire-view.js -o wwwroot/js/questionnaire-view.js -t [ babelify --presets [ #babel/preset-env #babel/preset-react ] --plugins [ #babel/plugin-transform-modules-commonjs ] ]
The output JS file looks okay and does not throw any errors in dev tools but when I go to call a function I get the following:
Error: Microsoft.JSInterop.JSException: Could not find 'collectQuestions' ('collectQuestions' was undefined).
Error: Could not find 'collectQuestions' ('collectQuestions' was undefined).
at http://localhost:41131/_framework/blazor.server.js:1:288
at Array.forEach (<anonymous>)
at r.findFunction (http://localhost:41131/_framework/blazor.server.js:1:256)
at v (http://localhost:41131/_framework/blazor.server.js:1:1882)
at http://localhost:41131/_framework/blazor.server.js:1:2662
at new Promise (<anonymous>)
at et.beginInvokeJSFromDotNet (http://localhost:41131/_framework/blazor.server.js:1:2643)
at http://localhost:41131/_framework/blazor.server.js:1:62750
at Array.forEach (<anonymous>)
at et._invokeClientMethod (http://localhost:41131/_framework/blazor.server.js:1:62736)
Any help is greatly appreciated :)
I ended up using webpack with babel loader:
var devJSConfig = Object.assign({}, config, {
mode: 'development',
entry: [
path.resolve(__dirname, './Scripts/Components/base-component.js'),
path.resolve(__dirname, './Scripts/address-view.js'),
path.resolve(__dirname, './Scripts/customer-view.js'),
path.resolve(__dirname, './Scripts/questionnaire-view.js')
],
output: {
path: path.resolve(__dirname, 'wwwroot/js'),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: '/node_modules/',
use: [
{
loader: 'babel-loader',
options: {
presets: [
"#babel/preset-env"
]
}
}
]
}
]
}
});
In my _Host.cshtml I had the script tag type attribute for my js files set to 'text/javascript' when it needs to be 'module'. I was also linking the individual script files but only needed to reference the bundle js which was produced using the above.
Lastly in my script I had to expose the js class to the Window like so (place this at the end of your js class):
window['QuestionnaireView'] = new QuestionnaireView();
I could then call js functions in my Blazor component class using:
var test = await jSRuntime.InvokeAsync<Object>("QuestionnaireView.collectQuestions");
I am following a course on Udemy which is about Wordpress development. Following the course I came up with this problem, I was trying to add google maps to a custom post type, for that I needed to update javascript file. But whenever I am running 'gulp scripts', this error occurs. I have no idea about node, gulp, webpack. I am just following the course. I looked up on the internet for a long time on this issue but found nothing.
I am using XAMPP. And before this, 'gulp watch' was working fine and php scripts were getting updated just fine.
gulpfile.js:-
var gulp = require('gulp'),
settings = require('./settings'),
webpack = require('webpack'),
browserSync = require('browser-sync').create(),
postcss = require('gulp-postcss'),
rgba = require('postcss-hexrgba'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import'),
mixins = require('postcss-mixins'),
colorFunctions = require('postcss-color-function');
gulp.task('styles', function() {
return gulp.src(settings.themeLocation + 'css/style.css')
.pipe(postcss([cssImport, mixins, cssvars, nested, rgba, colorFunctions, autoprefixer]))
.on('error', (error) => console.log(error.toString()))
.pipe(gulp.dest(settings.themeLocation));
});
gulp.task('scripts', function(callback) {
webpack(require('./webpack.config.js'), function(err, stats) {
if (err) {
console.log(err.toString());
}
console.log(stats.toString());
callback();
});
});
gulp.task('watch', function(done) {
browserSync.init({
notify: false,
proxy: settings.urlToPreview,
ghostMode: false
});
gulp.watch('./**/*.php', function(done) {
browserSync.reload();
done();
});
gulp.watch(settings.themeLocation + 'css/**/*.css', gulp.parallel('waitForStyles'));
gulp.watch([settings.themeLocation + 'js/modules/*.js', settings.themeLocation + 'js/scripts.js'], gulp.parallel('waitForScripts'));
done();
});
gulp.task('waitForStyles', gulp.series('styles', function() {
return gulp.src(settings.themeLocation + 'style.css')
.pipe(browserSync.stream());
}))
gulp.task('waitForScripts', gulp.series('scripts', function(cb) {
browserSync.reload();
cb()
}))
webpack.config.js:-
const path = require('path'),
settings = require('./settings');
module.exports = {
entry: {
App: settings.themeLocation + "js/scripts.js"
},
output: {
path: path.resolve(__dirname, settings.themeLocation + "js"),
filename: "scripts-bundled.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
}
]
},
mode: 'development'
}
settings.js:
exports.themeLocation = '/wp-content/themes/fictional-university-theme/';
exports.urlToPreview = 'localhost/imuni';
I had the same error the solution is simple add a DOT before /wp-content/:
exports.themeLocation = './wp-content/themes/fictional-university-theme/';
exports.urlToPreview = 'localhost/imuni';
Is there a way in webpack to restrict what files can be imported?
Say I want to be able to import files that are in the same directory, as well as the parent directory, but nothing above that parent directory? For example:
These work
import { blah } from "./script.js";
import { blah2 } from "./../gui/textbox.js";
import { blah3 } from "./../I/can/go/as/deep/down/as/I/want/here.js";
But this wouldn't work
import { passwords } from "./../../passwords.txt";
Because that would go up two (or x number of) directories, instead of just one.
You can create a loader to restrict webpack imports to specific files.
// file: webpack.config.js
const path = require('path');
module.exports = {
...
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: path.resolve('my-webpack-loader.js'),
options: {/* ... */}
}
]
}
]
}
};
Then throw if the resource file is outside ./src and ./node_modules directory or any directory of your choice.
// file: my-webpack-loader.js
const { getOptions } = require('loader-utils');
const validateOptions = require('schema-utils');
const path = require('path');
const schema = {
type: 'object',
properties: {
test: {
type: 'string'
}
}
};
function handler(source) {
const options = getOptions(this);
if(this.resourcePath.indexOf(path.resolve('./node_modules')) !== 0) {
if(this.resourcePath.indexOf(path.resolve('./src')) !== 0) {
throw `Reseource loading restricted for ${this.resourcePath}`;
}
}
validateOptions(schema, options, 'My Webpack Loader');
return source;
}
module.exports = handler;
For more info see writing a webpack loader.
react-dev-utils has a plugin for this.
This Webpack plugin ensures that relative imports from app's source
directories don't reach outside of it.
var path = require('path');
var ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
module.exports = {
// ...
resolve: {
// ...
plugins: [
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
// ...
],
// ...
},
// ...
};
I just started to use webpack and am trying to load jquery synchronously
Here is my main.js
var $ = require('jquery');
require('javascript/index.js');
require('less/index.less');
and here is my webpack.config
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var path = require('path');
module.exports = {
entry: './assets/javascript/main.js',
output: {
path: './assets',
filename: '/javascript/bundle.js'
},
module : {
loaders : [
{
test: /\.css/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
},
{
test: /\.less$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
}
]
},
plugins: [
new ExtractTextPlugin("/css/[name].css")
],
resolve : {
root: path.resolve('./assets'),
extensions: ['', '.js', '.less']
}
};
my index.js looks like this
$(document).ready(function () {
var body = $('body');
var backgrounds = new Array(
'url(./../images/bg1.jpg)' ,
'url(./../images/bg2.jpg)' ,
'url(./../images/bg3.jpg)' ,
'url(./../images/bg4.jpg)'
);
var current = 0;
function nextBackground() {
console.log("Changing bg");
current++;
current = current % backgrounds.length;
body.css('background-image', backgrounds[current]);
}
setInterval(nextBackground, 1000);
body.css('background-image', backgrounds[0]);
});
and on execution throws the error
Uncaught ReferenceError: $ is not defined
I really don't understand this error since if I look into the generated bundle.js Jquery clearly is getting defined.
I already tried to add this to my resolve:
resolve : {
root: path.resolve('./assets'),
extensions: ['', '.js', '.less'],
alias: {
jquery: "jquery"
}
}
but the error is still persistent
Edit: Here is a snipped of the created bundle.js
var $ = __webpack_require__(2);
__webpack_require__(3);
__webpack_require__(4);
According to your code, you need to add this to your index.js
var $ = require('jquery');
That's because when you used the webpack to build your code, each files(e.g index.js) would be wrap into a function which is defined by webpack.
So all the variables defined in your main.js are not accessable to index.js, coz they are now in different function which are not sharing the same scope.
You can either expose jquery to global(window) use the expose-loader or you need to require the jquery manually.
Hope this can solve your problem. : )
What you are looking for is the ProvidePlugin:
Automatically loaded modules. Module (value) is loaded when the identifier (key) is used as free variable in a module. The identifier is filled with the exports of the loaded module.
For example:
Add this plugin to your config:
new webpack.ProvidePlugin({
$: "jquery"
})
Somewhere in your code:
// in a module
$("#item") // <= just works
// $ is automatically set to the exports of module "jquery"
Make sure you got jquery installed via NPM
I am building a basic blog project to practice using React, ES6, and Mocha test framework. I'm having trouble transpiling my ES6 tests and app code within my default Gulp task.
I get this error when I run the default task and change the contents of ./test/posts.js for the watch to take effect:
[11:17:29] Using gulpfile ~/WebstormProjects/blog/gulpfile.js
[11:17:29] Starting 'default'...
[11:17:29] Finished 'default' after 8.54 ms
stream.js:75
throw er; // Unhandled stream error in pipe.
^
Error: invalid argument
at pathToArray (/Users/christian/WebstormProjects/blog/node_modules/memory-fs/lib/MemoryFileSystem.js:44:10)
at MemoryFileSystem.mkdirpSync (/Users/christian/WebstormProjects/blog/node_modules/memory-fs/lib/MemoryFileSystem.js:139:13)
at MemoryFileSystem.(anonymous function) [as mkdirp] (/Users/christian/WebstormProjects/blog/node_modules/memory-fs/lib/MemoryFileSystem.js:279:34)
at Compiler.<anonymous> (/Users/christian/WebstormProjects/blog/node_modules/webpack/lib/Compiler.js:229:25)
at Compiler.applyPluginsAsync (/Users/christian/WebstormProjects/blog/node_modules/tapable/lib/Tapable.js:60:69)
at Compiler.emitAssets (/Users/christian/WebstormProjects/blog/node_modules/webpack/lib/Compiler.js:226:7)
at Watching.<anonymous> (/Users/christian/WebstormProjects/blog/node_modules/webpack/lib/Compiler.js:54:18)
at /Users/christian/WebstormProjects/blog/node_modules/webpack/lib/Compiler.js:403:12
at Compiler.next (/Users/christian/WebstormProjects/blog/node_modules/tapable/lib/Tapable.js:67:11)
at Compiler.<anonymous> (/Users/christian/WebstormProjects/blog/node_modules/webpack/lib/CachePlugin.js:40:4)
Process finished with exit code 1
webpack.config.js
var path = require('path');
var babel = require('babel-loader');
module.exports = {
entry: {
app: './app/js/blog.js',
test: './test/posts.js'
},
output: {
filename: '[name].bundle.js',
path: './build',
sourceMapFilename: '[name].bundle.map'
},
watch: true,
devtool: '#sourcemap',
module: {
loaders: [
{
loader: 'babel',
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
query: {
presets: ['react', 'es2015']
}
}
],
resolve: {
root: path.resolve('./app'),
extensions: ['', '.js']
}
}
};
gulpfile.js
var gulp = require('gulp');
var webpack = require('webpack-stream');
var watch = require('gulp-watch');
var babel = require('babel-loader');
var named = require('vinyl-named');
gulp.task('default', function() {
watch(['./app/**/*.js', './test/*.js'], function() {
return gulp.src(['./app/js/blog.js', './test/posts.js'])
.pipe(named())
.pipe(webpack(require('./webpack.config.js')))
.pipe(gulp.dest('./build'));
});
});
gulp.task('testBundle', function() {
gulp.src('./test/posts.js')
.pipe(webpack(require('./webpack.config.js')))
.pipe(gulp.dest('./build'));
});
posts.js
import expect from 'expect'
import { post, posts, addPost } from '../app/js/blog'
import { createStore } from 'redux'
describe('Blog', () => {
describe('posts', () => {
it('should be able to create a post', () => {
let store = createStore(posts);
store.dispatch(addPost('First Post', 'Blah blah blah'))
let blah = { id: 'First Post', content: 'Blah blah blah'}
expect(store.getState()).toEqual(blah)
});
it('should be able to create multiple posts', () => {
let store2 = createStore(posts);
store2.dispatch(addPost('Second Post', 'Shh'))
let expectedState1 = { id: 'Second Post', content: 'Shh' }
expect(store2.getState()).toEqual(expectedState1)
store2.dispatch(addPost('Third Post', 'Whatever'))
let expectedState2 = { id: 'Third Post', content: 'Whatever'}
expect(store2.getState()).toEqual(expectedState2)
})
});
});
Ultimately, I'd like the transpiled code to be found at ./build/blog.bundle.js and ./build/posts.bundle.js for ./app/js/blog.js and ./test/posts.js, respectively.
There were some issues with my webpack.config.js and gulpfile.js. Apparently, the path property within the output object in webpack.config.js was conflicting with gulp.dest('./build'). I also reformatted some things in the config file to mirror a working one. Below is the code that should work. Hopefully this helps others trying to accomplish the same thing.
I have gulp starting webpack to produce separate bundle files for app and test entry points. I also get sourcemaps for each of the bundles that are created. Now I can write tests and app code in ES6 and run them with Mocha within WebStorm!
gulpfile.js
var gulp = require('gulp');
var webpack = require('webpack-stream');
var watch = require('gulp-watch');
gulp.task('default', function() {
watch(['./app/**/*.js', './test/*.js'], function() {
return gulp.src(['./app/js/blog.js', './test/posts.js'])
.pipe(named())
.pipe(webpack(require('./webpack.config.js')))
.pipe(gulp.dest('./build'));
});
});
gulp.task('webpack', function() {
return gulp.src(['./app/js/blog.js', './test/posts.js'])
.pipe(named())
.pipe(webpack(require('./webpack.config.js')))
.pipe(gulp.dest('./build'));
});
webpack.config.js
var path = require('path');
var babel = require('babel-loader');
module.exports = {
entry: {
app: './app/js/entry.js',
test: './test/posts.js'
},
output: {
filename: '[name].bundle.js',
sourceMapFilename: '[name].bundle.map'
},
devtool: '#source-map',
module: {
loaders: [
{
loader: 'babel',
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
query: {
presets: ['react', 'es2015']
}
}
]
},
resolve: {
root: path.resolve('./app'),
extensions: ['', '.js']
}
};
entry.js
import { posts } from './blog'
import { createStore } from 'redux'
createStore(posts)
blog.js
const posts = (state = [], action) => {
switch (action.type) {
case 'ADD_POST':
return post(undefined, action)
default:
return state
}
}
const post = (state = {}, action) => {
switch (action.type) {
case 'ADD_POST':
return { id: action.name, content: action.content }
}
}
// action creator
const addPost = (name, content) => {
return {
type: 'ADD_POST',
name,
content
}
}
export { posts, post, addPost }