Background
I'm trying to setup a Yii2 project with Browserify to manage JS dependancies. As Yii2 places JS and CSS dependancies in the vendor/bower directory, i'm trying to configure Browserify to use this as the include path for vendor dependancies.
I have a Grunt task setup to run my js build.
Problem
When I try to compile my js files using the Grunt task I am getting an error trying to find React (the first include in my js project).
Error: Cannot find module 'react' from '{my-working-directory}/modules/contact/asset/js'
Code
I have React installed (bower install) and available in my vendor/bower directory. My project JS src files i'm trying to build are located in modules/contact/asset/js/. In my JS files i'm including React at the top of the file.
modules/contact/asset/js/main.jsa
var React = require('react');
var component = React.createClass({
render: function() {
...
}
});
...
I have setup my Grunt browserify task with the include paths so that browserify knows how to find my includes, I have additionally added the react transform so that the JSX gets compiled into js.
Gruntfile.js
...
browserify: {
options: {
transform: [ require('grunt-react').browserify ],
browserifyOptions: {
paths: [
'./vendor/bower/',
'./modules/contact/asset/js/'
]
}
},
client: {
src: [
'./modules/contact/asset/js/*.js'
],
dest: './modules/contact/web/js/main.min.js'
}
},
...
Question
Why is browserify not able to find react or other includes?
You can't and should't access to vendor directory from web. If your website loaded from web folder, then you can only access only files and folders in web directory.
You can use AssetBundle to register scripts from vendor/bower directory:
class ReactAsset extends AssetBundle
{
public $sourcePath = '#bower';
public $js = [
'react/react.js'
];
}
See more in documentation.
Related
I'm using Webpack to build my front end components.
I have some React components which need classic webpack bundling, though I also have some vanilla JS files.
Those latter files are independent, so they won't get imported from React files. From my understanding, they need to be defined as entrypoints, so that Webpack reads and processes them. So far, so good.
The trouble is that I'd like Webpack to load them with Babel, and that's all, only give me back the JS file processed through Babel, I'm not interested in a bundle for these files.
Is it possible to do that? Only get the result of the babel loader, and not produce a bundle for some entrypoints?
Maybe I shouldn't use Webpack at all for these files?
Or maybe I should just set these bundles as 'library' so that I can reach them from the HTML pages?
What do you think guys?
Thanks by advance ;)
depends on how easy it is to find these files. I have a project that has similar requirement. What I have done is:
1/ put the vanilla js file in third_party/lib/
2/ import/require them in my current project
3/ set up my webpack.config.js as follows:
module.export = {
module: {
rules: [{
test : /.js$/,
exclude : /node_modules|third_party/,
loaders : ['babel-loader' /* other loaders? */],
},{
test : /third_party.*?\.js$/,
use: [{
loader : 'babel-loader' // or other loaders
},{
loader: 'file-loader'
options: {
name : '[path][name].[ext]',
outputPath : 'dist/third_party'
}
}]
}]
}
}
oh, you will need to npm i --save-dev file-loader
edit: I should clarify that this will bundle the vanilla js file as separate files to your main bundle, so you will have to import them by script tags yourself in your html file. (or if they were worker files, called by your script)
I have Node.js project and the following structure of folders:
lib
awesome-formatter.js
FrontEndApp
prettify.js
node_modules
awesome-parser
BackEndApp
...
I use awesome-parser module and awesome-formatter.js library in prettify.js script like this:
require('awesome-parser')
require('../lib/awesome-formatter.js')
awesome-formatter.js, in turns, should use awesome-parser too:
require('awesome-parser')
My FrontEndApp has been configured to use Webpack, and I'm trying to run it in dev mode using npm run dev command. However, I got the following error:
ERROR Failed to compile with 1 errors
These dependencies were not found:
* awesome-parser in /home/user/dev/lib/awesome-formatter.js
I don't want to move awesome-formatter.js inside the FrontEndApp because I also use it in BackEndApp project (and probably in some other projects) and I don't want to create separate "node_modules" in "lib" for it just not to duplicate installed modules on disk.
So, my question is, how to make Webpack use project's "node_modules" in js scripts located outside the project folder?
P.S. Of course there are workarounds like symlinks or making a full-featured module (with package.json etc.) from lib/awesome-fromatter and installing it into FrontEndApp/node_modules, but is there a direct way to solve this problem?
I've found a solution: resolve.modules sould be added to Webpack configuration file.
module.exports = {
...
resolve: {
...
modules: [
'node_modules',
resolve('node_modules')
]
},
...
}
This means that Webpack is searching modules in 'node_modules' as a relative subfolder (and it's the usual behavior), and at the absolute path to the project's 'node_modules' as well: resolve('node_modules'), so that scripts in folders outside the project (like lib in my structure) can find and use it.
I'm trying to create a React library. The components imports Sass files as follow:
import "./cp.scss";
class Cp extends Component {
render() {...}
}
To do so i'm using babel to compile the library into es5 by adding the following script:
package.json
...
"scripts": {
...
"compile": "babel -d lib/ src/"
}
It works fine, i'm getting a component looking like that:
...
var Cp = function (_Component) {
...
exports.default = Cp;
excepted that Babel is not able to handle my Sass file. So when i try to import a component in another project i got the following error
Module not found: Error: Cannot resolve 'file' or 'directory' ./cp.scss in ...
With webpack i manage to compile my library into a single js files. But i want to keep the files structure (like material-ui do) so i can import components from others apps like import {Cp} from 'library'.
Is there a way to achieve the same library output using wepback or whatever to handle the Sass files ?
I'm currently trying to integrate an npm module into an application that is built on Angularjs 1.4, Grunt, and Bower.
Require and Import do not work in the angualrjs framework which is the only way I can think of accessing the node_modules folder.
Does anyone have any idea how to use both npm and bower modules in the same application?
Here is a very trimmed down version of my app.js folder:
(function(angular) {
'use strict';
angular
.module('AppApp', [dependencies])
.constant('appconfig',{})
.config(function(...){
$statprovider.state{...}
.run(function($state){
$state.go('login);
})
})(angular);
I currently get all my dependencies through bower and access via index.html file. This does not seem to work if I write a script tag linking to the node_modules folder there.
USING MODULE INJECTION IN ANGULARJS
Accessing AngularJS modules from node_modules and bower_components is straight forward:
Let's take an example of angular-bootstrap from node_modules (Similar can be done from bower_components):
In HTML file, specify the reference of js file.
<script type="text/javascript" src="../node_modules/angular-bootstrap/ui-bootstrap-tpls.js"></script>
In your angular module, register the dependency as (You can check the module name on npm website or github while downloading or you can check it in the js files in node_modules/bower_components after downloading):
angular.module('AppApp',
[
'*ui.bootstrap*',
]);
However, you can also make Require and Import work in the AngularJS framework. This can be done using browserify or webpack that bundles your all the javascript files containing require/import into one to resolve the dependencies so that browser can understand require/import syntax, which is otherwise not understood by browsers.
USING BROWSERIFY
For using browserify when using grunt (app.js is the file containing require, you can specify other files in the array),
browserify: {
options: {
browserifyOptions: {
debug: true,
insertGlobalVars: []
},
transform: ['brfs' ]
},
app: {
files: {
['app.js']
}
}
}
node_modules dependencies required to use browserify are: brfs, grunt-browserify
I start to learn react js and they say on the react website "We recommend using React with a CommonJS module system like browserify"
So I used browserify with a simple hello world react component. Finally it produces an output file bundle.js of 651 ko (just for a simple hello world).
With this file bundle.js, I no longer have to include the scripts react.js and react-dom.js in my webpage, so I concluded that the file bundle.js includes my component and the react library.
But if I creates many components, I will have some javascript files and after the browserify transformation, each output files will be big because each files contains the react library. it will produce only one output file.
So I don't understand why they recommend to use browserify rather than just include react.js and react-dom.js library into my webpage and also my components js files after a babel transformation?
For development it is better not to minify. You apply minify when you go to production. For example with gulp;
gulp.task('appjs', function(){
browserify({ debug: true })
.transform(babel.configure({stage: 0}))
.require(source.appjs, { entry: true })
.bundle()
.pipe(vsource('app.min.js'))
.pipe(gulp.dest('./ui-dist'));
});
gulp.task('buildapp', function(){
browserify({ debug: false })
.transform(babel)
.require(source.appjs, { entry: true })
.bundle()
.pipe(vsource('app.min.js'))
.pipe(vbuffer())
.pipe(uglify())
.pipe(gulp.dest('./ui-dist'));
});
I think your question is about the size of the bundle file (the resulted file of browserify build), you worry about the time it will take when loaded on the page. This is some really important things you should know :
1. you don't have to include all your files in one bundle : you can generate multiple bundles. For example, you can configure browserify to create one bundle for your vendor files, and one or multiple bundles for your components.
in Dev mode, you don't have to minify your bundle,
For prod, you should generate your bundle using the react prod mode and minification.
To achieve point 1 (multiple bundles), here is an example with grunt browserify plugin.
var jsFiles = {
jsSrcFiles: './src/main/js/vs/**/*.js*', // my js and jsx source files
jsLibs: [
// vendor libs that I want to put in separate bundle
'react/addons',
...
]
};
...
browserify: {
app: {
options: {
transform: ['reactify'],
extensions: ['.jsx'],
// Here is where I tell browserify not to bundle vendor files with my source files
external: jsFiles.jsLibs
},
src: [jsFiles.jsSrcFiles],
dest: buildParams.js + '/vs_app.js'
},
// here is where I build vendor files in separate bundle named vendor.js
vendor: {
src: ['.'],
dest: buildParams.js + '/vendor.js',
options: {
alias: jsFiles.jsLibs
}
}
}...
Browserify is a great tool when it comes to small projects, when your project becomes more complex, browserify config tends to be very complex. In order to have more control of your built bundles, I recommend to use webpack, which is also a tool that facebook recommends. It allows easy bundling customization...