angularJS + webpack - production build not work - angularjs

This is the structure of my project
This is the webpack configuration
var ExtractTextPlugin = require('extract-text-webpack-plugin'),
webpack = require('webpack');
module.exports = {
entry: [
'./src/app.js',
],
output: {
path: __dirname + '/../web/js',
filename: 'build.js',
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.png$/,
loader: "url-loader?limit=100000"
},
{
test: /\.jpg$/,
loader: "file-loader"
},
{
test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-woff'
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader'
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=image/svg+xml'
},
]
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
'window.jQuery': "jquery"
}),
new ExtractTextPlugin('build.css')
]
}
This is app.js (entry point for webpack)
import 'babel-polyfill';
import $ from 'jquery';
window.$ = $;
import 'jquery-ui-dist/jquery-ui';
import 'bootstrap/dist/js/bootstrap.js';
import 'bootstrap/dist/css/bootstrap.css';
import 'angular';
import 'angular-ui-sortable';
import './styles.css'
import './controller/app.js'
This is controller/app.js (angular app)
import './racks.js'
import './deletedRacks.js'
import './switches.js'
import './deletedSwitches.js'
const myApp = angular.module(
'myApp',
[
'RacksListController',
'DeletedRacksListController',
'SwitchesListController',
'DeletedSwitchesListController',
'ui.sortable'
],
function($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
}
);
This is controller (for example use deletedRacks.js)
(function (window, angular) {
'use strict';
angular.module('DeletedRacksListController', []).controller('DeletedRacksListController', [
'$scope', '$http', function ($scope, $http) {
$scope.racks = [];
$scope.init = () => {
$http({
method: 'GET',
url: Routing.generate('racks_get_deleted')
}).then((response) => {
$scope.racks = response.data;
}, (e) => {
console.log(e)
});
};
$scope.restore = (rack) => {
$http.post(Routing.generate('racks_toggle_delete', {id: rack.id, token: rack.token})).then((response) => {
rack.delete = false;
}, (e) => {
console.log(e)
});
};
}
])
})(window, window.angular);
When I collect the project on the dev mode - everything works well. No errors appear in the console. If I collect the project on the the production mode (npm run build) I get the following error in the console:
Uncaught Error: [$injector:modulerr] Failed to instantiate module myApp due to:
Error: [$injector:unpr] Unknown provider: t
http://errors.angularjs.org/1.6.4/$injector/unpr?p0=t
I ask for your help.

This is controller/app.js (angular app)
import './racks.js'
import './deletedRacks.js'
import './switches.js'
import './deletedSwitches.js'
const myApp = angular.module(
'myApp',
[
'RacksListController',
'DeletedRacksListController',
'SwitchesListController',
'DeletedSwitchesListController',
'ui.sortable'
],
function($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
}
);
The error is in this file. $interpolateProvider is not injected. Correctly so:
import './racks.js'
import './deletedRacks.js'
import './switches.js'
import './deletedSwitches.js'
const myApp = angular.module(
'myApp',
[
'RacksListController',
'DeletedRacksListController',
'SwitchesListController',
'DeletedSwitchesListController',
'ui.sortable'
]
);
myApp.config(['$interpolateProvider', function($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
}]);

Related

TemplateCache of NPM Modules not loading (AngularJS 1.X and Webpack)

I created a angular 1.x project using fountain-angular yeoman generator with webpack for module management.
I then added angular-strap as a dependency to this project.
Now when i try to use angular-strap plugins like tabs or select in my application, am not able to get the corresponding template of these components loaded. Got the below console error.
Error: [$compile:tpload] Failed to load template: tab/tab.tpl.html (HTTP status: undefined undefined)
Am not sure if i have to change anything in webpack config file to get these templates loaded fine. Below is what my config looks like now.
const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const FailPlugin = require('webpack-fail-plugin');
const autoprefixer = require('autoprefixer');
module.exports = {
module: {
rules: [
{
test: /\.json$/,
loaders: [
'json-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre'
},
{
test: /\.(css|scss)$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
config: {
path: './postcss.config.js'
},
plugins: () => [require('autoprefixer')]
},
},
'sass-loader',
]
},
{
test: /\.js$/,
exclude: /node_modules/,
loaders: [
'ng-annotate-loader',
'babel-loader'
]
},
{
test: /\.html$/,
loaders: [
'html-loader'
]
}
]
},
plugins: [
new webpack.ProvidePlugin({
moment: 'moment',
agGrid: 'ag-grid'
}),
new webpack.ContextReplacementPlugin(/\.\/locale$/, 'empty-module', false, /js$/),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
FailPlugin,
new HtmlWebpackPlugin({
template: conf.path.src('index.html')
}),
new webpack.LoaderOptionsPlugin({
options: {
postcss: () => [autoprefixer]
},
debug: true
})
],
devtool: 'source-map',
output: {
path: path.join(process.cwd(), conf.paths.tmp),
filename: 'index.js'
},
entry: `./${conf.path.src('index')}`
};
Below is my index.js file.
import angular from 'angular';
import 'angular-sanitize';
import 'angular-toastr';
import 'todomvc-app-css/index.css';
import {TodoService} from './app/todos/todos';
import {App} from './app/containers/App';
import {Header} from './app/components/Header';
import {MainSection} from './app/components/MainSection';
import {TodoTextInput} from './app/components/TodoTextInput';
import {TodoItem} from './app/components/TodoItem';
import {Footer} from './app/components/Footer';
import 'angular-ui-router';
import 'angular-strap';
import 'angular-cookies';
import '#exalink/ui-components/dist/xl.ui-components';
import routesConfig from './routes';
import * as agGrid from 'ag-grid';
import './index.scss';
agGrid.initialiseAgGridWithAngular1(angular);
angular
.module('app', ['ngSanitize', 'ngCookies', 'agGrid', 'mgcrea.ngStrap', 'ui.router', 'toastr', 'xl.uiComponents'])
.config(routesConfig)
.service('todoService', TodoService)
.component('app', App)
.component('headerComponent', Header)
.component('footerComponent', Footer)
.component('mainSection', MainSection)
.component('todoTextInput', TodoTextInput)
.component('todoItem', TodoItem);
Below is my header.html, am adding the below template that uses bs-tabs from angular-strap.
<div bs-active-pane="$ctrl.tabs.activeTab" bs-tabs>
<div ng-repeat="tab in $ctrl.tabs" data-title="{{ tab.title }}" name="{{ tab.title }}" disabled="{{ tab.disabled }}" ng-bind="tab.content" bs-pane>
</div>
</div>
I believe am missing something pretty straight forward and simple. Am pretty new to webpack and any help would be appreciated.
You imported only
import 'angular-strap';
but still need to include angular-strap.tpl.min.js
http://mgcrea.github.io/angular-strap/
import 'angular-strap.tpl.js' as well

injecting ui-router-metatags to fountain js angularjs project

Hey I am trying to use ui-router-metatags module in my project but it never works.
https://github.com/tinusn/ui-router-metatags
I followed the steps but at the end nothing. it is not showing error even.
I use yeoman fountain js generator for angular js and webpack.
I do npm install ui-router-metatags --save
this is my index.js file
var angular = require('angular');
var techsModule = require('./app/modules/techs/index');
require('angular-ui-router');
require('expose-loader?$!jquery');
var routesConfig = require('./routes');
var main = require('./app/main');
var header = require('./app/shared/header');
var title = require('./app/shared/title');
var footer = require('./app/shared/footer');
import 'bootstrap';
require('./index.scss');
angular
.module('app', [techsModule, 'ui.router', 'ui.router.metatags'])
.config(routesConfig)
.component('app', main)
.component('fountainHeader', header)
.component('fountainTitle', title)
.component('fountainFooter', footer);
function runBlock($rootScope, MetaTags) {
$rootScope.MetaTags = MetaTags;
}
angular
.module('app')
.run(['$rootScope', 'MetaTags', runBlock]);
function myService() {
var service = {
getPosts: getPosts,
getPost: getPost
};
var samplePost = {
id: 1,
title: 'sample blog post',
content: 'lorem ipsum'
};
function getPosts(category) {
return [samplePost];
}
function getPost(id) {
return samplePost;
}
return service;
}
angular
.module('app')
.service('myService', myService);
and my routes.js look like that.
module.exports = routesConfig;
/** #ngInject */
function routesConfig($stateProvider, $urlRouterProvider, $locationProvider, UIRouterMetatagsProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
UIRouterMetatagsProvider
.setTitlePrefix('prefix - ')
.setTitleSuffix(' | MyApp')
.setDefaultTitle('MyApp')
.setDefaultDescription('description')
.setDefaultKeywords('keywords')
.setStaticProperties({
'fb:app_id': 'your fb app id',
'og:site_name': 'your site name'
})
.setOGURL(true);
$urlRouterProvider.otherwise('/');
$stateProvider.state('app', {
url: '/',
component: 'app',
metaTags: {
title: 'Frontpage',
description: 'This is the frontpage',
keywords: 'lots of interresting keywords',
properties: {
'og:title': 'Frontpage'
}
}
});
}
and for my html page I use this:
<title ng-bind="MetaTags.title">Default title</title>
<meta name="description" content="{{MetaTags.description}}">
<meta name="keywords" content="{{MetaTags.keywords}}">
<meta ng-repeat="(key, value) in MetaTags.properties" property="{{key}}" content="{{value}}">
<meta name="prerender-status-code" content="{{MetaTags.prerender.statusCode}}">
<meta name="prerender-header" ng-if="MetaTags.prerender.header" content="{{MetaTags.prerender.header}}">
and for my web pack config I have this:
const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const FailPlugin = require('webpack-fail-plugin');
const autoprefixer = require('autoprefixer');
module.exports = {
module: {
rules: [
{
test: require.resolve('jquery'),
use: [
{loader: 'expose-loader', options: 'jQuery'},
{loader: 'expose-loader', options: '$'}
]
},
{
test: require.resolve('tether'),
use: [
{loader: 'expose-loader', options: 'Tether'}
]
},
{
test: /\.json$/,
loaders: [
'json-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre'
},
{
test: /\.(css|scss)$/,
loaders: [
'style-loader',
'css-loader',
'sass-loader',
'postcss-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules/,
loaders: [
'ng-annotate-loader'
]
},
{
test: /\.html$/,
loaders: [
'html-loader'
]
}
],
loaders: [
{
test: /\.json$/,
loaders: [
'json-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre'
},
{
test: /\.(css|scss)$/,
loaders: [
'style-loader',
'css-loader',
'sass-loader',
'postcss-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules/,
loaders: [
'ng-annotate-loader'
]
},
{
test: /\.html$/,
loaders: [
'html-loader'
]
},
{test: require.resolve('jquery'), loader: 'expose-loader?$'}
]
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
FailPlugin,
new HtmlWebpackPlugin({
template: conf.path.src('index.html')
}),
new webpack.LoaderOptionsPlugin({
options: {
postcss: () => [autoprefixer]
},
debug: true
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
tether: 'tether',
Tether: 'tether',
'window.Tether': 'tether',
Popper: ['popper.js', 'default'],
// In case you imported plugins individually, you must also require them here:
Util: 'exports-loader?Util!bootstrap/js/dist/util',
Dropdown: 'exports-loader?Dropdown!bootstrap/js/dist/dropdown'
})
],
devtool: 'source-map',
output: {
path: path.join(process.cwd(), conf.paths.tmp),
filename: 'index.js'
},
node: {
fs: 'empty'
},
entry: `./${conf.path.src('index')}`
};

How to use CSS Modules with webpack in React isomorphic app?

I am build an isomorphic app using react, react-router, express and webpack. Now I want to use css modules to import css.
I use import './index.css' in index.jsx, it works fine on client, but doesn't work on server rendering. The error is Error: Cannot find module './index.css'.
components/index.jsx
import React, {Component, PropTypes} from 'react';
import style from './index.css';
class App extends Component {
constructor(props, context) {
super(props, context);
}
render() {
return (
<div id="login">
// ...
</div>
);
}
};
export default App;
server/router/index.js
import url from 'url';
import express from 'express';
import swig from 'swig';
import React from 'react';
import {renderToString} from 'react-dom/server';
import {match, RouterContext} from 'react-router';
import routes from '../../client/routes/routes';
import DataWrapper from '../../client/container/DataWrapper';
import data from '../module/data';
const router = express.Router();
router.get('*', async(req, res) => {
match({
routes,
location: req.url
}, async(error, redirectLocation, props) => {
if (error) {
res.status(500).send(error.message);
} else if (redirectLocation) {
res.status(302).redirect(redirectLocation.pathname + redirectLocation.search);
} else if (props) {
let content = renderToString(
<DataWrapper data={data}><RouterContext {...props}/></DataWrapper>
);
let html = swig.renderFile('views/index.html', {
content,
env: process.env.NODE_ENV
});
res.status(200).send(html);
} else {
res.status(404).send('Not found');
}
});
});
export default router;
webpack.config.dev.js(for webpack-dev-server)
var webpack = require('webpack');
var config = require('./config');
module.exports = {
devtool: 'inline-source-map',
entry: [
'webpack-dev-server/client?http://localhost:' + config.webpackPort,
'webpack/hot/only-dev-server',
'./src/client/entry',
],
output: {
path: __dirname + '/public/js',
filename: 'app.js',
publicPath: 'http://localhost:' + config.webpackPort + '/public/js',
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify('development')
}
})
],
resolve: {
extensions: ['', '.js', '.jsx', '.css']
},
module: {
loaders: [{
test: /\.jsx?$/,
loader: 'react-hot',
exclude: /node_modules/
}, {
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
}, {
test: /\.css$/,
loader: 'style-loader!css-loader?modules',
exclude: /node_modules/
}, {
test: /\.(png|woff|woff2|svg|ttf|eot)$/,
loader: 'url-loader',
exclude: /node_modules/
}]
}
}
I'd recommend using webpack to compile UI code for both client and server side in that case. Just set target: "node" in webpack config to produce bundle which can executed in Node environment.
That article might help for compiling your server side code with Webpack: http://jlongster.com/Backend-Apps-with-Webpack--Part-I
Especially on how to exclude node_modules with the externals key.
A very bare config might look like:
'use strict';
const path = require('path');
const fs = require('fs');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const rootDir = path.resolve(__dirname, '..');
const distDir = path.join(rootDir, 'dist');
const srcDir = path.join(rootDir, 'src');
const localStyles = new ExtractTextPlugin('local.css', { allChunks: true });
const nodeModules = fs.readdirSync('node_modules')
.filter(dir => !dir.startsWith('.'))
.reduce((acc, prop) => {
acc[prop] = 'commonjs ' + prop;
return acc;
}, {});
const loaders = [
{
test: /\.(js|jsx)$/,
include: srcDir,
exclude: /node_modules/,
loader: 'babel',
query: {
cacheDirectory: true,
},
},
{
test: /\.css$/,
include: srcDir,
loader: localStyles.extract(
'style',
'css?modules&localIdentName=[name]-[local]_[hash:base64:5]'
),
},
{
test: /\.json$/,
loader: 'json',
},
];
module.exports = {
target: 'node',
entry: {
server: ['server/index'],
},
output: {
path: distDir,
filename: '[name].bundle.js',
},
externals: nodeModules,
module: {
loaders,
},
plugins: [
localStyles,
],
};
Another solution (Webpack free) could be to use babel-plugin-css-modules-transform
.

Element type is invalid with React Component

I seem to be running into an issue, Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.. Cannot figure out why this is happening with the given code below.
In client.js,
'use strict';
import DefaultLayout from 'custom_module/lib/bundle';
import transService from './transservice';
const translator = transService.createTranslator(CLI_CONTEXT);
ReactDOM.render(
<div>
// Seems to be where the error occurs
<DefaultLayout translator={translator} title={'app.title'}/>
</div>,
document.getElementById('react-container')
);
In DefaultLayout.jsx,
'use strict';
import 'uikit';
import React from 'react';
import Layout from './common_components/layout.jsx';
class DefaultLayout extends React.Component {
constructor(props) {
super(props);
}
componentWillReceiveProps(nextProps) {
document.title = this.props.translator(this.props.title);
}
componentDidMount() {
document.title = this.props.translator(this.props.title);
}
render() {
return (
<div>
<Layout translator={this.props.translator}>
<div>{this.props.children}</div>
</Layout>
</div>
);
}
}
export default DefaultLayout;
I package the DefaultLayout.jsx into a custom_module with Webpack and Gulp using the following config,
module.exports = function(paths) {
var webpack = require('webpack'),
ManifestPlugin = require('webpack-manifest-plugin'),
env = require('./gulpenv'),
externals = [],
plugins = [];
const vendorPackages = [
'jquery',
'uikit'
];
plugins.push(new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(env.IS_DEV)
}));
plugins.push(new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js', Infinity));
plugins.push(new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
jquery: 'jquery',
"window.jQuery": "jquery"
}));
var webpackConfig = {
name: 'Build Client Side',
entry: {
bundle: './src/client/javascripts/DefaultLayout.jsx',
vendor: vendorPackages
},
bail: true,
output: {
filename: '[name].js'
},
module: {
loaders: [{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react', 'stage-0']
}
}, {
test: /\.(scss|sass)$/,
loader: 'style!css!sass'
}, {
test: /uikit\/dist\/js\//,
loader: 'imports?jQuery=jquery,$=jquery,this=>window'
}]
},
resolve: {
modulesDirectories: ['node_modules'],
extensions: ['', '.js', '.jsx']
},
plugins: plugins
}
return webpackConfig;
};
My Jade template looks like,
doctype html
html
head
link(rel="stylesheet", type="text/css", href="/stylesheets/bundle.css")
link(rel="stylesheet", type="text/css", href="/stylesheets/style.css")
body
block content
script(type="text/javascript").
var CLIENT_CONTEXT = {
language: '#{language}',
logging: '!{clientlogger}'
};
script(type="text/javascript", src="/javascripts/vendor.bundle.js")
script(type="text/javascript", src="/javascripts/bundle.js")
script(type="text/javascript", src="/javascripts/client.js")

_angular.angular undefined error when loading angular app built by webpack

I am trying to bootstrap an AngularJS app built with Webpack. But I get the following error and the module isn't set up.
TypeError: _angular.angular is undefined
I dig into the generated code chunk and find that the _angular.angular is from
var _angular = __webpack_require__(1);
var _angularUiBootstrap = __webpack_require__(3);
_angular.angular.module('app', [_angularUiBootstrap.bootstrap]).constant('_', window._).run(function ($rootScope) {
$rootScope._ = window._;
It looks like that _angular.angular.module should be _angular.module. I probably use a wrong way to bootstrap angular, or use an incorrect Webpack configuration. Here is my code:
webpack.config.js
var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var srcDir = 'static_src';
var outputDir = 'static';
module.exports = {
devtool: 'source-map',
debug: true,
entry: {
app: path.resolve(srcDir, 'app.js')
},
output: {
path: outputDir,
filename: '[name].bundle.js',
sourceMapFilename: '[name].map',
chunkFilename: '[id].chunk.js'
},
resolve: {
extensions: ['', '.js', '.less', '.css'],
alias: {
npm: __dirname + '/node_modules'
}
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['es2015'],
plugins: ['syntax-decorators', 'ng-annotate']
},
exclude: /node_module/
},
{ test: /\.less$/, loader: 'to-string!css!less' },
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader') },
{ test: /\.(png|gif|jpg)$/, loader: 'file?name=images/[name].[ext]' }
]
},
plugins: [
new webpack.NoErrorsPlugin(),
new webpack.optimize.DedupePlugin(),
new ExtractTextPlugin('[name].css')
]
};
app.js
import { angular } from 'angular';
import { bootstrap } from 'angular-ui-bootstrap';
angular.module('app', [bootstrap]);
I am using angular 1.5.0 and webpack 1.12.14.
Thanks in advance.
your error is in the require statement. you are using
import { angular } from 'angular';
this implies that there is an angular variable inside of the exported angular module.
what you want to use is
import angular from 'angular';
try that.

Resources