I have a HTML-based project and I am using a bower.json to get all the dependencies together:
{
"name": "MyProject",
"version": "0.1",
"main": "index.html",
"dependencies": {
"modernizr": "2.8.3",
"classie": "1.0.1",
"jquery": "2.1.1",
"font-awesome": "4.2"
}
}
The whole thing is in git and I don't want to checkin the bower_components directory. So I want to move the libraries into my project using some sort of script mechanism.
The situation:
I want to have the following directory structure:
index.html
css
main.css
js
main.js
lib
js
jquery
jquery.min.js
css
jquery-ui
jquery-ui.min.css
fonts
...
Some libs not only have .js files but also css as well as font files
Some libraries (e.g. font awesome) reference files within the library structure
Update
I cam up with a rake script based approach (See below). But I wonder, if there is a more elegant approach based on Javascript / NodeJS
would it be easier to use a .gitignore file?
I think its okay if you use git ignore to avoid bower_components and node_modules. but what you need there is .bowerrc file with this:
{
"directory": "app/libs"
}
with that route you can specified the destination folder.
and your bower.json
{
"name" : "test",
"version": "0.1",
"dependencies" : {
"jquery-ui" : "latest"
},
"install" : {
"path" : {
"css": "src/css",
"js": "src/js"
},
"sources" : {
"jquery-ui" : [
"components/jquery-ui/ui/jquery-ui.custom.js",
"components/jquery-ui/themes/start/jquery-ui.css"
]
}
}
}
or it can be possible as well using a task runner like grunt or gulp
I came up with the following solution, which is based on a Rake script:
desc 'Copy the bower libs to the projects sources'
task :copy_libs do
js_lib = 'js/lib'
`rm -fr #{js_lib}`
`mkdir -p #{js_lib}`
libraries = {
js: [
'jquery/dist/jquery.min.js',
'jquery/dist/jquery.min.map',
'modernizr/modernizr.js',
'classie/classie.js'
],
css: [
'font-awesome/css/font-awesome.min.css'
],
fonts: [
'font-awesome/fonts/fontawesome-webfont.woff',
'font-awesome/fonts/fontawesome-webfont.ttf',
'font-awesome/fonts/fontawesome-webfont.svg',
]
}
bower = 'bower_components'
libraries.each do |type,libs|
`mkdir -p lib/#{type}`
libs.each do |lib|
`cp #{bower}/#{lib} lib/#{type}/`
end
end
end
Related
I want to generate multiple pages which will have content on different languages from one common template. How can I do it with webpack?
I tried to use different webpack plugins like webpack-static-i18n-html, i18n-webpack-plugin but nothing works for me. The best thing I found is a webpack-static-i18n-html, but it has bad support and this plugin can't watch changes in JSON files with translated text. Below is what I have for now.
This is my code from webpack.common.js.
const Path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const StaticI18nHtmlPlugin = require("webpack-static-i18n-html");
//...
module.exports = {
//...
plugins: [
//...
new StaticI18nHtmlPlugin({
locale: 'en',
locales: ['en', 'ua', 'ru'],
baseDir: Path.posix.join(__dirname, ".."),
outputDir: 'src/localized-pages',
outputDefault: '__lng__/__file__',
localesPath: 'src/locales',
files: 'src/templates/index.html'
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: Path.resolve(__dirname, '../src/templates/index.html')
}),
new HtmlWebpackPlugin({
filename: 'ua/index.html',
template: Path.resolve(__dirname, '../src/localized-pages/ua/src/templates/index.html')
}),
new HtmlWebpackPlugin({
filename: 'ru/index.html',
template: Path.resolve(__dirname, '../src/localized-pages/ru/src/templates/index.html')
}),
//...
],
//...
};
I also have webpack.dev.js and webpack.prod.js which I merge with webpack.common.js via webpack-merge plugin. As you can see, after generating pages, I have to use HtmlWebpackPlugin to serve them. It's awkward to use.
locales folder:
locales
|-en.json
|-ua.json
|-ru.json
en.json file:
{
"key": {
"innerKey" : "value"
}
}
Then plugin generates from:
<p data-t>key.innerKay</p>
this
<p>value</p>
But as I said, If I change en.json nothing will regenerate. I will not use this way to generate multiple pages for different languages.
So, I would like to generate several pages from one template. Is there any way to do this with webpack?
I was working on a multi language admin dashboard with Webpack and was wondering how could I tackle this problem until I found a way to make everything automatic with a multiple language web template.
First of all, webpack-static-i18n-html isn't a good solution because most of its packages are deprecated. But actually the mentioned package is based on a good npm package called node-static-i18n. So, the first thing you need to do is installing this npm package using this command
npm install -g static-i18n
Next, you need to make your translation file as *.json files and in json format and put them in a folder which I named "locales" and I put it in my "src" folder of my project. I need two languages for my website. One of them is English and another is Farsi or Persian. Therefore I made two file namely fa.json and en.json. So, I have folder and file structure like the picture below:
My file and folder structure in my Webpack project
This is part of my en.json file as an example:
{
"menu": {
"items": {
"dashboard": "Dashboard",
"posts": "Posts",
"media": "Media"
},
"sub": {
"items": {
"all-posts": "All Posts",
"add-new-post": "Add New",
"categories": "Categories"
}
}
}
}
This is part of my fa.json file as an example:
{
"menu": {
"items": {
"dashboard": "پیشخوان",
"posts": "نوشته ها",
"media": "رسانه"
},
"sub": {
"items": {
"all-posts": "نوشته ها",
"add-new-post": "افزودن نوشته",
"categories": "دسته ها"
}
}
}
}
and you can use them in your html tags like this:
<span class="className" data-t>menu.items.dashboard</span>
Please notice that for using translation you should use the attribute data-t in your tags like span then you can use key and values saved in your related json file to use translations between your tags. for more information about data-t and its usage please go to the plugin's Github page that I mentioned it earlier in this text on the plugin name.
Next, you should write needed command in the script section of your package.json file to run node-static-i18n to translate your template based on your html template file and save them in i18n folder in root of your project as below:
"scripts": {
"i18n": "static-i18n -l en -i fa -i en src --localesPath src/locales/",
}
in the above command:
-l: The default locale.
-i: the list of locales to be generated.
--localesPath: The directory of the translations, where each file should be named LOCALE_NAME.json
Now if you run npm run i18n this command should make a folder in root path of your project called i18n containing html files in two languages in this case. it will be like the picture below:
i18n folder and translated html files in it
Next you should config your Html Webpack Plugin in your Webpack config file to show these pages in your browser like this:
plugins: [
.
.
.
new HtmlWebpackPlugin({
//inject: false,
chunks: ['main'],
template: 'i18n/index.html',
filename: 'index.html'
}),
new HtmlWebpackPlugin({
//inject: false,
chunks: ['main-rtl'],
template: 'i18n/fa/index.html',
filename: 'fa/index.html'
})
]
because you need to see changes on your browser automatically you need another package called npm-watch to install through this command:
npm install -D npm-watch
Then, you should change script section of your package.json like this:
"scripts": {
"i18n-watch": "watch 'npm run i18n' src",
"i18n": "static-i18n -l en -i fa -i en src --localesPath src/locales/",
}
By using the command npm run i18n-watch whenever you make any changes in your locale files or your original html template in src folder it's gonna re-translate your html file based on new information and if you're running your webpack dev server you can see the result right after you save changes.
After that, to run i18n-watch command and your Webpack dev server at the same time it would be great installing another npm package for this purpose called npm-run-all by using the command below:
npm i -D npm-run-all
Finally, you can change the script section of your package.json like this to run i18n-watch and your Webpack dev server at the same time and after that if you make any changes you can see the result in the browser right after saving changes.
"scripts": {
"i18n-watch": "watch 'npm run i18n' src",
"i18n": "static-i18n -l en -i fa -i en src --localesPath src/locales/",
"webpack-dev": "webpack-dev-server --open --config=config/webpack.dev.js",
"start": "npm-run-all --parallel webpack-dev i18n-watch"
}
Now, if you use npm start in your terminal you will see your Webpack dev server and i18n-watch are running at the same time watching for any changes.
Hopefully this makes sense.
As I mention, I want to import a module but I don't understand the document.
I'm using Ionic for develop an app.
I install the module :
npm install wordnet
Instead of using ..
var wordnet = require('wordnet');
wordnet.lookup('define', function(err, definitions) {
definitions.forEach(function(definition) {
console.log(' words: %s', words.trim());
console.log(' %s', definition.glossary);
});
});
How to use the module in the Typescript file for using it function.. as
import { wordnet } from 'wordnet'
Do I need to import module in app.module.ts or in the page page.module.ts or something...?
It depends on your setup. If you're using AngularCLI, then it should find the TypeScript / JavaScript code automagically. Check your node-modules directory to make sure the code is there. If not add the --save-dev flag when you install:
npm install --save-dev wordnet
IF this library relies on binary assets or CSS files, then you may have to edit the angular-cli.json file to tell it where to find image or CSS files. Here is a snippet from the AngularCLI conversion I did in my Learn With books that shows how I set up assets and CSS.
"apps": [
{
"assets": [
"img",
{
"glob": "**/*",
"input": "../node_modules/#swimlane/ngx-datatable/release/assets/fonts",
"output": "./fonts"
}
],
"styles": [
"styles.css",
"../node_modules/bootstrap/dist/css/bootstrap.css",
"../node_modules/#swimlane/ngx-datatable/release/assets/icons.css",
"../node_modules/#swimlane/ngx-datatable/release/themes/material.css"
],
}
],
If you're using SystemJS to load modules then you'll have to set up wordnet in your SystemJS config. Generally something like this:
(function (global) {
System.config({
map: {
'wordnet': 'path/to/wordnet/code'
},
});
})(this);
How can I switch this to avoid using bower?
I installed yeoman for the first time and the generator for knockoutjs use bower. Now I read bower support is limited and bootstrap use popper.js which in v2 will deprecate support for bower. I would like to avoid the headache now and learn at the same time.
RequireJS and every client side libraries is in /src/bower_modules.
If I install bootstrap using npm or yarn it will install them in /node_modules, which the browser doesn't have access.
Do I then use gulp to transfer the dist folder to my /src/bower_modules folder?
Folder structure:
/src/
|--bower_modules/
|--app/
|--require.config.js
/node_modules/
/gulpfile.js
gulpfile.js:
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: 'bower_modules/requirejs/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' ]
}
}),
transpilationConfig = {
root: 'src',
skip: ['bower_modules/**', 'app/require.config.js'],
babelConfig: {
modules: 'amd',
sourceMaps: 'inline'
}
},
babelIgnoreRegexes = transpilationConfig.skip.map(function(item) {
return babelCore.util.regexify(item);
});
app/require.config.js:
var require = {
baseUrl: ".",
paths: {
"bootstrap": "bower_modules/bootstrap/js/bootstrap.min",
"crossroads": "bower_modules/crossroads/dist/crossroads.min",
"hasher": "bower_modules/hasher/dist/js/hasher.min",
"popper": "bower_modules/popper.js/dist/popper",
"jquery": "bower_modules/jquery/dist/jquery",
"knockout": "bower_modules/knockout/dist/knockout",
"knockout-projections": "bower_modules/knockout-projections/dist/knockout-projections",
"signals": "bower_modules/js-signals/dist/signals.min",
"text": "bower_modules/requirejs-text/text"
},
shim: {
"bootstrap": { deps: ["popper", "jquery"] }
}
};
Sidenote: The origin of the issue is that I require popper for bootstrap and bootstrasp.bundle is not included in the bower version is seems. Also popper doesn't like bower very much and won't be supported very long. I also have multiple errors trying to include it. I would also like to learn the good way and since bower will not be around long I wouldn't mind not working with it at all.
Bower itself posted a blog about this recently: https://bower.io/blog/2017/how-to-migrate-away-from-bower/.
Here's the key takeaways:
Manually move any packages from bower.json to package.json that are available from both Bower and NPM
For any items that are only available via Bower you can use the bower-away NPM package to install those with NPM instead of Bower
Write a task runner script (Grunt/Gulp/etc...) to move the package(s) file(s) to your dist directory
Something like this should do it.
gulp.task('injectNpmPackages', function () {
return gulp.src([
path.join('/node_modules/my-package/build/my-package.min.js')
])
.pipe(gulp.dest('/dist/vendor/'));
});
I'm creating an application using Angular 2. I started using it in the RC2 phase and after alot of updates I made to my app according to the released RC I finally got it to run on the Angular 2.0.0 final version.
As I'm using the angular-cli as well and updated to the currently latest version (1.0.0-beta.15). I also did all the required changes needed as it e.g. now uses webpack instead of SystemJs.
My problem now is, that I can't seem to find a way to include external libraries (lets take jQuery for this example) to my application without the need to include from a CDN.
In previous versions of Angular 2 there was an angular-cli-build.js like this:
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
'systemjs/dist/system-polyfills.js',
'systemjs/dist/system.src.js',
'zone.js/dist/**/*.+(js|js.map)',
'es6-shim/es6-shim.js',
'reflect-metadata/**/*.+(js|js.map)',
'rxjs/**/*.+(js|js.map)',
'#angular/**/*.+(js|js.map)',
'jquery/dist/*.min.+(js|map)'
]
});
};
Which (looking to the last line of the vendorNpmFiles array) mapped the jquery library to the folder of the ready build app together with the system-config.js which had a little something like this:
/** Map relative paths to URLs. */
const map: any = {
'jquery': 'vendor/jquery'
};
And what it did was creating a vendor folder inside the final build folder (by default called dist) from which I could simply import jquery from in my parent most index.html with a statement like:
<script src="vendor/jquery/dist/jquery.min.js"></script>
My question now is how to get a similar result as described in the angular-cli version I'm using.
For now I use the libraries globally so I include them in the angular-cli.json
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": "assets",
"index": "index.html",
"main": "main.ts",
"test": "test.ts",
"tsconfig": "tsconfig.json",
"prefix": "app",
"mobile": false,
"styles": [
"styles.css",
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"../node_modules/font-awesome/css/font-awesome.min.css"
],
"scripts": [
"../node_modules/jquery/dist/jquery.min.js",
"../node_modules/bootstrap/dist/js/bootstrap.min.js"
],
"environments": {
"source": "environments/environment.ts",
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
This way it is also not needed to include them into the index.html.
If someone finds another way to do it I'm still very interested in it.
The problem:
I cant get React.js to function at all in a requirejs and brunch situation.
I get a mismatched definition error with the react.js library, and react does not show up in the windows object.I am unsure as to what to do, and was hoping some one here had guidance in how resolve this issue. Perhaps I am using this combination of technology incorrectly, maybe it is not possible? Any insight into what I may be doing wrong or suggestions to resolve this problem would be greatly appreciated!
Btw, If I remove the bower reference to react.js, and remove all react.js information from the application, it all works correctly.
See my below edit for some additional comments and findings!
Actual error:
Error: Mismatched anonymous define() module: function (){var
define,module,exports;return (function e(t,n,r){function
s(o,u){if(!n[o]){if(!t[o]){var a=typeof
require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return
i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw
f.code="MODULE_NOT_FOUND",f}var
l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var
n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return
n[o].exports}var i=typeof require=="function"&&require;for(var
o=0;odereq,module,exports){*
The Project file structure is as follows:
Projectname
|-app
|-assets
|-index.html
|-components
|-appinit.js
|-styles
|-bower_components
|-react
|-requirejs
|-node_modules
|-public
|-bower.json
|-brunch.config
The brunch.config file, I believe is pretty standard, here are the contents:
exports.config = {
"modules": {
"definition" : "amd",
"wrapper" : "amd"
},
"files": {
"stylesheets": {
"defaultExtension": "css",
"joinTo": {
"css/app.css": /^app\/styles/,
"css/vendor.css": /^(bower_components|vendor)/
}
},
"javascripts": {
"joinTo": {
"js/app.js": /^app/,
"js/vendor.js": /^(bower_components|vendor)[\\/]/,
"test/js/test.js": /^test(\/|\\)(?!vendor)/,
"test/js/test-vendor.js": /^test(\/|\\)(?=vendor)/
},
"order": {
"before": [
'bower_components/requirejs/require.js'
]
}
}
}
};
Here are the contents for the index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>My Application Test</title>
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="/css/app.css">
<script src="/js/vendor.js"></script>
<script src="/js/app.js"></script>
<script>
require.config({
"paths": {
"react": "bower_components/react/react-with-addons"
},
"shim": {
"react": {
exports: "React"
}
},
waitSeconds: 10
});
require(["components/appinit"], function (appInit) {
appInit.init();
});
</script>
</head>
<body style="height:100%; width:100%;">
<div id="main-content" style="margin-left: 100px; margin-top: 22px;">
My Main Content Goes Here.
</div>
</body>
</html>
and the contents of the appinit.js file:
define(function() {
var mainModule;
return mainModule = {
init: function () {
console.log("This is a test.");
return mainModule;
}
};
});
The bower.json file contains the following:
{
"name": “brunchreactrequirejstest",
"version": "1.0.0",
"homepage": "",
"authors": [
“person x"
],
"description": “description",
"main": "public/js/app.js",
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"requirejs": "~2.1.15",
"react": "~0.12.2"
}
}
EDIT
So I believe I am getting closer to getting this resolved. I just found out that brunch only adds the definition wrappers around non-vendor javascript. So, react.js is being compiled to the vendor.js file without any definition name, so require.js throws the exception of react.js being anonymous. So, perhaps I need to have brunch run r.js on the vendor file during the compilation process? Does this sound correct? How do I go about doing that in brunch?
The React project does not provide an AMD interface out of the box, and as you noted in your edit this is not something Brunch will do for you on vendor files.
Your options appear to be either converting your project to use CommonJS module patterns or use an AMD adapter such as https://github.com/philix/jsx-requirejs-plugin.
Possible Solution:
So I have react now functioning in a requirejs(AMD) environment. There is one problem that I see with my approach, and that is that I believe some libraries that work with react expect react to be exposed as a global object.I believe I can probably shim this into the requirejs export.config() by creating a requirejs definition that manually places react into the browser window scope(more on this later.)
Following are the changes I have made that have allowed react to work in an AMD/RequireJS environment:
The (new) brunch.config file:
exports.config = {
"modules": {
"definition" : "amd",
"wrapper" : "amd"
},
"files": {
"stylesheets": {
"defaultExtension": "css",
"joinTo": {
"css/app.css": /^app\/styles/,
"css/vendor.css": /^(bower_components|vendor)/
}
},
"javascripts": {
"joinTo": {
"js/app.js": /^app/,
"js/vendor.js": /^(bower_components|vendor)[\\/](?!react\/)/,
"test/js/test.js": /^test(\/|\\)(?!vendor)/,
"test/js/test-vendor.js": /^test(\/|\\)(?=vendor)/
},
"order": {
"before": [
'bower_components/requirejs/require.js'
]
}
}
},
"plugins":{
"react": {
"harmony": "yes"
}
}
};
The (new) index.html 'head' now only consists of this:
<link rel="stylesheet" href="/css/app.css">
<script src="/js/vendor.js"></script>
<script src="/js/app.js"></script>
<script>
require(["components/appinit"], function (appInit) {
appInit.init();
});
</script>
The build.js file: So this file i created is executed by node.js when I call 'npm start' on the project, which you will see in the package.json file further below:
({
baseUrl: ".",
optimize: "none",
paths: {
react: "bower_components/react/react-with-addons"
},
name: "react",
out: "vendor/react-built.js"
})
basically, it assigns the bower path to the react path, and the name grabs the bower path so that it knows the location of the file that r.js will optimize. The require.js optimized file is then thrown into the vendor folder as react-built.js. If you recall from above, in my new brunch config file, I exclude the bower-react javascript library from being compiled into the final vendor.js file, because i will already be adding the requirejs optimized react library that is generated with this build.js file.
So the scripts section of the NPM package.json file looks like this:
"scripts": {
"start": "node node_modules/requirejs/bin/r.js -o build.js && brunch watch --server"
}
Essentially, when you call 'npm start', r.js is executed with the build.js file passed into it, afterwards brunch is called.
So the next part, as es128 has mentioned, is to get any JSX annotated files to get preprocessed into javascript before brunch wraps them for AMD inclusion.
== Edit
So installing the react-brunch plugin via npm works wonderfully. .jsx files get compiled to javascript upon saving the .jsx file. I updated the above brunch-config file with the plugin information. I have yet to shim and export React globally into the window scope, but I believe that may be a different StackOverflow topic since it does not relate to my original question.