browserify bundle doesn't handle importing files via relative path - javascript

I am using browserify and babel to compile and bundle my react app. The files from client/ are bundled up into a single file static/bundle.js. But I use a relative import which seems to not be handled correctly.
Here's my file structure
client/
components/
main.js
App.js
static/
bundle.js
gulpfile.js
and here's my gulpfile and the offending import
// client/App.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import App from './components/main.js';
render(
<App />,
document.getElementById('root'),
);
// gulpfile.js
var gulp = require('gulp');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');
gulp.task('build', function() {
browserify({
entries: 'client/App.js',
extensions: ['.js'],
debug: true
})
.transform(babelify, {presets: ['es2015', 'react']})
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest('static'));
});
The problem is the line import App from './components/main.js';.
When I look in static/bundle.js, there is a line var _main = require('./components/main.js');, which doesn't make sense because relative to bundle.js there is no ./components/main.js. That was defined relative to client/App.js.
Does browserify not handle such things and is there another tool I should be using in addition, or am I doing something else incorrect?

You have to add paths to your browserify options. If you do not add that browserify doesn't know where to look for to find your module.
module.exports = function(grunt){
grunt.initConfig({
browserify: {
options:{
browserifyOptions: {
// ...
paths: [
'./node_modules',
'./client'
]
}
},
// ...
},
// ...
});
}
This was an issue before they solve it.

Related

Using gulp scripts to minify js

So for some reason, I'm having some problems with my gulp scripts where gulp scripts won't write the appropriate js to the bundled file.
So I have the following folder structure:
theme/
- dist/
--- css/
----- bundle.css
--- js
----- bundle.js
- src/
--- scss/
----- bundle.scss
--- js/
----- bundle.js
----- components/
------- test.js
Here is the gulp styles task which works perfect - What it does is that it takes all of the contents inside src/scss/ and bundles it and exports it to dist/css/bundle.css.
export const styles = () => {
return src(['src/scss/bundle.scss', 'src/scss/admin.scss', 'src/scss/bulmapress.scss'])
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(cleanCss({compatibility:'ie8'})
.pipe(dest('dist/css'))
.pipe(server.stream());
}
My src/scss/bundle.scss file has the following:
#import "components/header";
#import "components/footer";
Here is the task that I have for gulp scripts where once I run the task, it doesn't compile the content inside src/js/components etc.. it compiled things that are inside src/js/bundle.js which is just a storage component to define import "components/test". Here is the task:
export const scripts = () => {
return src(['src/js/bundle.js'])
.pipe(dest('dist/js'));
}
I'm not sure what I'm doing wrong, or if this is natural behavior? What might be a better alternative to do this? Below is the full gulpfile.babel.js if anyone wants to check it out.
Would it be better for js to not be bundled into bundle.js and just be minimized into it's own separate file?
import { src, dest, watch, series, parallel } from 'gulp'; //import { src, dest, watch, series, parallel } from 'gulp';
import yargs from 'yargs';
import sass from 'gulp-sass';
import cleanCss from 'gulp-clean-css';
import gulpif from 'gulp-if';
import sourcemaps from 'gulp-sourcemaps';
import imagemin from 'gulp-imagemin';
import del from 'del';
import browserSync from "browser-sync";
import zip from "gulp-zip";
import info from "./package.json";
import replace from "gulp-replace";
const PRODUCTION = yargs.argv.prod;
const server = browserSync.create();
export const serve = done => {
server.init({
proxy: "http://localhost:8888/starter"
});
done();
};
export const reload = done => {
server.reload();
done();
};
export const styles = () => {
return src(['src/scss/bundle.scss', 'src/scss/admin.scss', 'src/scss/bulmapress.scss'])
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(cleanCss({compatibility:'ie8'})
.pipe(dest('dist/css'))
.pipe(server.stream());
}
export const scripts = () => {
return src(['src/js/bundle.js'])
.pipe(dest('dist/js'));
}
You have to transpile ES6 code to ES5 code using gulp-babel before you do uglification or minification.
Read this article about gulp tasks to understand how gulp works:
https://medium.com/#sudoanushil/how-to-write-gulp-tasks-ce1b1b7a7e81

Storybook fails to parse JSX from directories imported from anywhere behind the root directory

I have a simple storybook project which is structured as so:
├── .storybook
├── .babelrc
├── package.json
├── node_modules
├── stories
│ ├── index.js
and I can run my config with start-storybook -p 6006
// .storybook/config.js
import { configure } from '#storybook/react'
function loadStories() {
require('../stories/index.js')
}
configure(loadStories, module)
Now I want to include some components which are a directory behind. So the new file structure would be:
├── storybook
│ ├── .storybook
│ ├── .babelrc
│ ├── package.json
│ ├── node_modules
├── stories
│ ├── index.js
And my config now calls the stories from one directory back:
// ./storybook/.storybook/config.js
import { configure } from '#storybook/react'
function loadStories() {
require('../../stories/index.js')
}
configure(loadStories, module)
but it seems storybook is unable to parse the file now, even though the only change is that the story has been moved on file back. I get the following error:
ERROR in ../admin-components/components/Button/Button.js 40:26
Module parse failed: Unexpected token (40:26)
You may need an appropriate loader to handle this file type.
| import React from "react"
|
> const Button = (props) => <button>Click Me!!!</button>
|
| export default Button
# ../admin-components/components/Button/index.js 1:0-29 3:15-21
# ../admin-components/components/index.js
# ./stories/index.js
# ./.storybook/config.js
# multi ./node_modules/#storybook/core/dist/server/config/polyfills.js ./node_modules/#storybook/core/dist/server/config/globals.js ./.storybook/config.js ./node_modules/webpack-hot-middleware/client.js?reload=true
Do I need some custom parser config in my .babelrc or will this clash with the default storybook config. Perhaps there some setting for storybook to be able to handle this directory structure?
EDIT
Have tried adding further configuration to my webpack config to allow parsing of JSX but to no avail.
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = (storybookBaseConfig, configType) => {
storybookBaseConfig.resolve.alias = {
'prop-types$': path.join(__dirname, '../node_modules/axe-prop-types')
};
storybookBaseConfig.module.rules.push({
test: /\.(js|jsx)$/,
exclude: [/bower_components/, /node_modules/, /styles/],
loader: 'babel-loader',
include: path.resolve(__dirname, '../stories'),
query: {
presets: ['#babel/react']
}
});
storybookBaseConfig.plugins.push(new CopyWebpackPlugin([{ from: '.storybook/fonts', to: 'fonts' }]))
if (configType === 'PRODUCTION') {
config.optimization.minimize = false;
}
return storybookBaseConfig;
}
getting the following error:
ERROR in ./stories/index.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Plugin/Preset files are not allowed to export objects, only functions.
Why don't you place each story in same folder where component declared❔
And then in storybook config.js file include them:
import {configure} from '#storybook/react'
function loadStories() {
const req = require.context(`../src`, true, /\.stories\.jsx?$/)
req.keys().forEach(filename => req(filename))
}
configure(loadStories, module)
Example of a story:
import Icon from './index'
import React from 'react'
import {storiesOf} from '#storybook/react'
storiesOf(`Icons`, module)
.add(`Bell`, () => (
<Icon src="bell"/>
))
.add(`Settings`, () => (
<Icon src="settings"/>
))
.add(`User`, () => (
<Icon src="user"/>
))
Add this to storybook/.storybook/webpack.config.js
const path = require('path');
module.exports = async ({ config, mode }) => {
config.module.rules.push({
test: /\.js?$/,
include: path.resolve(__dirname, '../../stories'),
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: './node_modules/.cache/storybook',
presets: [
[ './node_modules/#babel/preset-env/lib/index.js',
{
shippedProposals: true, useBuiltIns: 'usage', corejs: '3'
}
],
'./node_modules/#babel/preset-react/lib/index.js',
'./node_modules/#babel/preset-flow/lib/index.js',
],
plugins: [],
},
},
],
});
config.resolve.modules = [
...config.resolve.modules,
path.resolve(process.cwd(), 'node_modules'),
]
// Return the altered config
return config;
};
You DO NOT NEED to have .babelrc.
Explanation:
In this link: Default config, you can see the default configuration and I just copied some of the configs there. It will handle the approriate loader for your js/jsx.
As for the config.resolve.modules, you need to tell the webpack that your node_modules folder is not in the root directory in the stories so that when you use modules outside storybook folder, it will see the modules.
Hope this helps.

mocha-webpack not finding tests

I can't seem to figure how to get mocha-webpack to detect tests in my folder. I'm running the following command:
mocha-webpack --webpack-config test/server/webpack.config-test.js
webpack.config-test.js
var nodeExternals = require("webpack-node-externals")
const path = require("path")
function resolve(dir)
{
return path.join(__dirname, "..", dir)
}
module.exports = {
context: path.resolve(__dirname),
resolve: {
extensions: [".js"],
alias: {
"vue$": "vue/dist/vue.esm.js",
"#": resolve("src"),
}
},
target: "node", // webpack should compile node compatible code
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
}
If it helps, I'm also using vue-cli, so there are already webpack configs, and maybe I could just import one of them then do slight changes.
You need to add this to your line of code:
mocha-webpack --webpack-config test/server/webpack.config-test.js \"src/**/*.js\"

React ES6 SystemJS - Uncaught (in promise) Error: Unexpected token <(…)

I have react and react-dom installed and imported in via the System.config below, but I still get this error below:
Uncaught (in promise) Error: Unexpected token <(…)
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ES2015 Module Example</title>
</head>
<body>
<script src="lib/system.js"></script>
<script>
System.config({
"baseURL": "src",
// Set defaultJSExtensions to true so you don't have to use .js extension when importing the es6 module.
"defaultJSExtensions": true,
// 'plugin-babel' or 'traceur' or 'typescript'
transpiler: 'traceur',
map: {
'react': './node_modules/react/dist/react.min.js',
'react-dom': './node_modules/react-dom/dist/react-dom.min.js',
'traceur': './lib/traceur.min.js',
'plugin-babel': './lib/plugin-babel/plugin-babel.js',
'systemjs-babel-build': './lib/plugin-babel/systemjs-babel-browser.js'
},
});
System.import("app.js");
</script>
</body>
<div id="example"></div>
</html>
app.js:
import React from 'react';
import ReactDOM from 'react-dom';
var Hello = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
ReactDOM.render(
<Hello name="World" />,
document.getElementById('example')
);
Any ideas what else do I have to configure?
browserify is the best solution (for production & development) - to me:
npm install --save-dev babel-preset-react
gulp:
var gulp = require('gulp');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var livereload = require('gulp-livereload');
gulp.task('build', function() {
// app.js is your main JS file with all your module inclusions
return browserify({entries: 'src/app.js', debug: true})
.transform("babelify", { presets: ["es2015", "react"] })
.bundle()
.pipe(source('compile.min.js'))
.pipe(buffer())
.pipe(sourcemaps.init())
.pipe(uglify())
.pipe(sourcemaps.write('./maps'))
.pipe(gulp.dest('js'))
.pipe(livereload());
});
gulp.task('default', ['build']);
As for non-production with SystemJS (painfully slow):
<!DOCTYPE html>
<script src="https://jspm.io/system#0.19.js"></script>
<script>
System.config({
transpiler: 'babel',
babelOptions: {}
});
System.import('./main.js');
</script>
You still can use gulp for development. Just add this to the gulpfile:
gulp.task('watch', ['build'], function () {
livereload.listen();
gulp.watch('js/*.js', ['build']);
});
gulp.task('default', ['watch']);
This saves you from other tedious dev workflows as listed here.
Unexpected token < usually occurs in html5 applications, when the server is configured to return the contents of index.html instead of 404 pages (so pressing f5 on dynamic routing still works). Check then network panel in your browsers developer console, and see which js file was served with html contents.

How can I bundle js files in my lib with main app.js

Right now, only my app.js and the files that I use inside it are being bundled. I want the files inside my libs to also be bundled together into that same js file. Here is my folder structure inside my js folder:
.
├── app.js
├── components
└── libs
└── materialize.min.js
And here is my gulpfile where I'm bundling them all together:
import gulp from 'gulp'
import source from 'vinyl-source-stream'
import buffer from 'vinyl-buffer'
import browserify from 'browserify'
import babelify from 'babelify'
import uglify from 'gulp-uglify'
import watchify from 'watchify'
const jsDirs = {
src: './client/js/app.js',
dest: './dist/js'
}
function buildBundle(b) {
b.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest(jsDirs.dest))
}
gulp.task('scripts', () => {
let b = browserify({
cache: {},
packageCache: {},
fullPaths: true
})
b = watchify(b.transform(babelify))
b.on('update', () => buildBundle(b))
b.add(jsDirs.src)
buildBundle(b)
})
gulp.task('default', ['scripts'])
Is there any way to include my libs js files which aren't being used by app.js?
you should be able to call b.require(path) multiple times. (that's how I do it for mine)
Something like :
import gulp from 'gulp'
import source from 'vinyl-source-stream'
import buffer from 'vinyl-buffer'
import browserify from 'browserify'
import babelify from 'babelify'
import uglify from 'gulp-uglify'
import watchify from 'watchify'
const jsDirs = {
src: './client/js/app.js',
dest: './dist/js',
requires: [
'./libs/materialize.min.js',
['./libs/whatever.js', 'whatever']
]
}
function buildBundle(b) {
b.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest(jsDirs.dest))
}
gulp.task('scripts', () => {
let b = browserify({
cache: {},
packageCache: {},
fullPaths: true
});
b = watchify(b.transform(babelify))
[].concat(jsDirs.requires || []).forEach(function (req) {
var path = req,
expose = null;
if (typeof path !== 'string') {
expose = path[1];
path = path[0]
}
b.require(path, expose ? { expose: expose } : {});
});
b.on('update', () => buildBundle(b))
b.add(jsDirs.src)
buildBundle(b)
})
gulp.task('default', ['scripts'])
this also let you expose the lib for futur requires

Categories

Resources