Why do Vue single file components compile to such large files? - javascript

I am new to Vue and Grunt/Gulp/Webpack. I got a Vue app to work fine (Grunt: browserify -> babel -> uglify) with a setup like this:
// app.js
const LoginComponent = require('./login.js')
// login.js
const template = `<some html>`
module.exports = Vue.component('login-component', {
template: template,
// component stuff
})
Then, in order to make my components more readable, I switched to single file components (Webpack, Grunt: babel -> uglify) and go everything to work like this:
// app.js
import LoginComponent from './login.js'
// login.js
<template>
<some html>
</template>
<script>
export defalut {
// component stuff
}
</script>
The problem is that when using webpack the file size is doubled. The first setup resulted in an app.min.js of 3.3kb, and the second setup with webpack was 7.0kb.
Is this normal or did I do something wrong?
My webpack.config.js looks like this:
var path = require('path')
module.exports = {
entry: './resources/js/app.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'resources/js/temp')
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
]
}
}

I don't see anything wrong with your config, sometimes webpack needs to generate some runtime code that might explain the increase of your bundle size.
However you can reduce it by using the DefinePlugin to set the NODE_ENV variable to production and leverage the UglifyjsWebpackPlugin, it will result in optimized code that will most likely be smaller, so something like the following
module.exports = {
entry: './resources/js/app.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'resources/js/temp')
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify('production') },
}),
new webpack.optimize.UglifyJsPlugin({ compressor: { warnings: false } }),
]
}
You can also specify the option dead_code to uglify so it trims out code that is never used, which might help in your case.
Also, you should get rid of Grunt entirely using the babel-loader and the appropriate presets.

Related

React : You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file(Local Node module)

I have babel loader in the library. Still after I add the library to the react application while yarn serve, I get the above error.
This is the webpack.dev.config.js (required in the webpack.config.js) in library-
//webpack.dev.config.js
const babelRCPath = require('#appfabric/infra-scripts').getConfigPath('babel', 'plugin');
const babelRCGenerator = require(babelRCPath);
const babelRC = babelRCGenerator([]);
module.exports = {
{
BaseModule: `${process.cwd()}/src/BaseModule`,
BaseObject: `${process.cwd()}/src/BaseObject`,
BaseWidget: `${process.cwd()}/src/widgets/BaseWidget`,
HOCWidget: `${process.cwd()}/src/widgets/HOCWidget`,
PortalWidget: `${process.cwd()}/src/widgets/PortalWidget`,
BaseActivator: `${process.cwd()}/src/application/BaseActivator`,
CorePlugin: `${process.cwd()}/src/application/CorePlugin`,
BaseAppDelegate: `${process.cwd()}/src/application/appdelegates/BaseAppDelegate`,
EmbeddedAppDelegate: `${process.cwd()}/src/default/appdelegates/embedded/EmbeddedAppDelegate`,
ActionType: `${process.cwd()}/src/application/appdelegates/actions/ActionType`,
types: `${process.cwd()}/src/application/appdelegates/actions/types`,
CommandActionType: `${process.cwd()}/src/application/appdelegates/actions/CommandActionType`,
CommandForResponseActionType: `${process.cwd()}/src/application/appdelegates/actions/CommandForResponseActionType`,
PluginRegistryService: `${process.cwd()}/src/default/PluginRegistryService`,
},
mode: 'development',
externals: [
'dcl',
'react',
'react-dom',
'prop-types',
'pubsub',
'semver',
'#appfabric/ui-profiler',
].map(
// Add this regex to each entry to ensure we don't miss any imports like 'web-shell-core/...`
(value) => new RegExp(`^(${value})((\\\\|/|!).+)?$`),
),
output: {
path: `${process.cwd()}/build/dist`,
filename: '[name].js',
library: 'web-shell-core',
libraryTarget: 'umd',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: babelRC,
},
},
],
},
};
This is the webpack.config.js
const developmentConfig = require('./webpack.dev.config.js');
module.exports = merge(developmentConfig, {
mode: 'production',
output: {
filename: '[name].min.js',
chunkFilename: '[name].min.js',
},
});
First I add a new file Secure.jsx(having the tags) in the library. I do npm install --save <path-to-library> on my application. After I do yarn install. Then I can see the new file Secure.jsx in the node modules in the application. When I try to run the application, I get the error.
Please let me know what am I missing and also which side(library / application) I have to add the code.
You can view my full config here
I think you also need to add this
resolve: {
modules: [
path.resolve('./node_modules')
]
},
Then import like this
import "jquery/dist/jquery.min.js";
import "bootstrap/dist/js/bootstrap.min.js";

Typescript: How to have some imports in the global scope?

Context:
I work on a project where the senior programmer decided to reduce the boilerplate code in newly created typescript files. Two examples of this boilerplate code would be importing the React library or the function that fetches and processes our localized strings.
Question:
Is it possible to have imports always available in files placed in certain folders without having to write the import tags every time?
What I've tried:
I've searched and read on the subject and found those links that talk about defining variables to use in the global space:
global.d.ts, global-modifying-module.d.ts, A typescript issue that seems to get it working
However, I was still unable to get it to work. Here is what I've tried:
At the root of the folder where I want React to be always available, I created a global.d.ts file which contains:
import * as R from "react";
declare global{
const React: typeof R;
}
With this file, the resource "React" is supposed to always be available to other files in subsequent folders. My IDE (Webstorm) recognizes that the import is there and allows me to manipulate the variable React without complaining. However, when I try to run the app, I get this error:
ReferenceError: React is not defined
I don't understand what is wrong with the code! Here is an example of the file I'm trying to render:
export default class World extends React.Component<{}, any> {
public render() {
return (<div>Hello world</div>);
}
}
From this stackoverflow question, I was under the impression that the problem could be webpack related. For the sake of completeness, here is the webpack config file we're currently using:
const webpack = require('webpack');
const path = require('path');
const BUILD_DIR = path.resolve(__dirname, './../bundles');
const WEBPACK_ENTRYFILE = path.resolve(__dirname, './../srcReact/ReactWrapper.tsx');
// `CheckerPlugin` is optional. Use it if you want async error reporting.
// We need this plugin to detect a `--watch` mode. It may be removed later
// after https://github.com/webpack/webpack/issues/3460 will be resolved.
const { CheckerPlugin } = require('awesome-typescript-loader');
const config = {
entry: [WEBPACK_ENTRYFILE],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.less']
},
output: {
path: BUILD_DIR,
filename: 'bundle.js'
},
plugins: [
new CheckerPlugin()
],
devtool: 'source-map', // Source maps support ('inline-source-map' also works)
module: {
loaders: [
{
loader: 'url-loader',
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.(ts|tsx)$/,
/\.css$/,
/\.less$/,
/\.ttf/,
/\.woff/,
/\.woff2/,
/\.json$/,
/\.svg$/
],
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
loader: 'url-loader',
test: /\.(ttf|woff|woff2)$/
},
{
loader: "style-loader!css-loader!less-loader",
test: /\.less$/
},
{
loader: "style-loader!css-loader",
test: /\.css$/
},
{
loader: "svg-loader",
test: /\.svg$/
},
{
loader: "json-loader",
test: /\.json$/
},
{
loader: "awesome-typescript-loader",
test: /\.(ts|tsx)$/
}
]
}
};
module.exports = config;
I am certain I am missing something. Can anyone help me?
Surely already open followed a tutorial like this
To do this creates a vendor file where you import these types of "global".
./src/vendors.ts;
import "react";
Add this file a to first place at entry parameter:
entry: { 'vendors': './src/vendors.ts', 'main': './src/main.ts' }
And add CommonChunkPlugins:
plugins: [ new CommonsChunkPlugin({
name: 'vendors'
}),
Like this in AngularClass with polyfills.

Failed to load scss with webpack

I'm using webpack, and I want to load scss file in my JavaScript. (Or if it can be separate, it also fine).
This is my webpack config:
"use strict";
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');
module.exports = {
context: __dirname + '/src',
entry: './js/index.js',
output: {
path: './build',
filename: 'js/app.bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}
]
},
resolve: {
root: [
path.resolve('./src/js'),
path.resolve('./src/scss')
],
extensions: ['', '.js']
},
plugins: [
new CopyWebpackPlugin([
{ from: 'html/**', to: `${__dirname}/build/html`, flatten: true },
{ from: 'images/**', to: `${__dirname}/build/image`, flatten: true }
])
]
};
this is my files list:
src/html/index.html -> build/html/index.html (WORKED)
src/images/** -> build/images/** (WORKED)
src/js/index.js -> build/js/app.bundle.js (WORKED)
src/scss/** -> build/css/** (NOT WORKED)
This is my JavaScript code. I just started project, so not much codes:
import "babel-polyfill";
import React from 'react';
import ReactDOM from 'react-dom';
import moduleA from 'moduleA';
import "view/startup.scss";
ReactDOM.render(
<div>
<h1>Helloworld!</h1>
</div>,
document.getElementById('entry')
);
You can see this: import "view/startup.scss";
I want to load scss file into my JavaScript, but when I run webpack command, it says:
ERROR in Loader /Users/.../Desktop/work/my-project/app/node_modules/css/index.js didn't return a function
# ./scss/view/startup.scss 4:14-123
in "resolve" property of webpack config, you can see that I added another root directory for scss, also I loaded sass-loader too, but it doesn't work and I don't know why.
And as I know, with Webpack, including css/scss automatically injects into destination file, so it doesn't matter it needs to be extract as separate file, I just want that this works.
Any help will be very appreciated :)
* UPDATED *
code of ./scss/view/startup.scss
#startup {
background-color: #7087d7;
}
The error points towards the reason (I highlighted the relevant part):
ERROR in Loader /Users/.../Desktop/work/my-project/app/node_modules/css/index.js didn't return a function # ./scss/view/startup.scss 4:14-123
When you declare a loader in Webpack, you can leave off the -loader suffix (so css-loader becomes css) provided that you don't have other modules that may match the suffixless loader name.
This is where it fails in your case, because you also use the css package, which Webpack tries to use as a loader (and fails, because it's not).
To fix this, use the full loader package name:
loaders : [ "style-loader", "css-loader", "sass-loader" ]

webpack - compile every scss to css file with same name

I'd like to have structure like this
-Styles
--Main.scss
--SomeComponent.scss
-CompiledStyles
--Main.css
--SomeComponent.css
Actually I can only do this
-Styles
--Main.scss
--SomeComponent.scss
--All.scss (import all scss from file)
-CompiledStyles
--Main.css ( all css)
This is my webpack config
var Path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var extractCSS2 = new ExtractTextPlugin('[name].css');
module.exports = {
devtool: 'eval',
entry: './Client/Styles/All.scss',
output: {
path: Path.join(__dirname, 'CompiledStyles'),
filename: 'page.js',
publicPath: '/CompiledStyles/'
},
module: {
loaders: [
{
test: /\.scss$/,
loader: extractCSS2.extract("style-loader", "css-loader!autoprefixer-loader!sass-loader")
},
{
//IMAGE LOADER
test: /\.(jpe?g|png|gif|svg)$/i,
loader: 'file-loader'
},
{
test: /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
loader: 'file-loader?name=fonts/[name].[ext]'
}
]
},
plugins: [
extractCSS2
]
};
Is it possible to compile this scss files to single css files ?
I really don't know how to manage this case. I've tried to assign entry: './Client/Styles' but it occures error.
EDIT:
I solved this with gulp.
The idea of webpack is to put everything that is needed in some JavaScript-files. So it's the intention to not build a css-file for every css-file.
If you want to still use webpack, try this in your webpack config:
module.exports = {
// ...
entry: {
'Main': './Client/Styles/Main.scss',
'SomeComponents': './Client/Styles/SomeComponents.scss',
},
// ...
}
I have updated the answer after adamo94 noted that he used gulp, so just for everybody else some more information. To convert scss files you need a sass/scss-processor. You can easily call that processor with a single call but as you usually do more with your sources it's likely to use some further processing.
Usually you would use gulp or grunt. Those can be configured to build everything that you need. They have different pros and cons, there are also further tools, but those are probably the ones that you'd like to take a look.

What is the best practice for importing angularjs using webpack?

How do you use Webpack and AngularJS together, and how about template loading and on demand fetching of resources?
An example of a well written webpack.config.js file for this purpose would be very much appreciated.
All code snippets displayed here can be accessed at this github repo. Code has been generously adapted from this packetloop git repo.
webpack.config.json
var path = require('path');
var ResolverPlugin = require("webpack/lib/ResolverPlugin");
var config = {
context: __dirname,
entry: ['webpack/hot/dev-server', './app/app.js'],
output: {
path: './build',
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.css$/,
loader: "style!css-loader"
}, {
test: /\.scss$/,
loader: "style!css!sass?outputStyle=expanded"
}, {
test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/,
loader: "file"
}, {
test: /\.html$/,
loader: "ngtemplate?relativeTo=" + path.join(__dirname, 'app/') + "!raw"
}]
},
// Let webpack know where the module folders are for bower and node_modules
// This lets you write things like - require('bower/<plugin>') anywhere in your code base
resolve: {
modulesDirectories: ['node_modules', 'lib/bower_components'],
alias: {
'npm': __dirname + '/node_modules',
'vendor': __dirname + '/app/vendor/',
'bower': __dirname + '/lib/bower_components'
}
},
plugins: [
// This is to help webpack know that it has to load the js file in bower.json#main
new ResolverPlugin(
new ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
)
]
};
module.exports = config;
To import AngularJS into the main app.js you do the following:
app/vendor/angular.js
'use strict';
if (!global.window.angular) {
require('bower/angular/angular');
}
var angular = global.window.angular;
module.exports = angular;
And then use it in app.js like so,
app.js
...
var angular = require('vendor/angular');
// Declare app level module
var app = angular.module('myApp', []);
...
Is the following correct? Is there an easier way to do this? I've seen a few (not a lot by any standards) posts which listed another method.
From this reddit post comment
// Add to webpack.config.js#module#loaders array
{
test: /[\/]angular\.js$/,
loader: "exports?angular"
}
There is also another plugin which is in development right now, at stackfull/angular-seed. It seems to be in the right direction, but is really really hard to use right now.
Webpack is way awesome, but the lack of documentation and samples are killing it.
You can just require angular in all modules (files) where you need it. I have a github repository with example how to do that (also using webpack for build). In the example ES6 import syntax is used but it shouldnt matter, you can use standard require() instead.
Example:
import 'bootstrap/dist/css/bootstrap.min.css';
import './app.css';
import bootstrap from 'bootstrap';
import angular from 'angular';
import uirouter from 'angular-ui-router';
import { routing} from './app.config';
import common from './common/common.module';
import featureA from './feature-a/feature-a.module';
import featureB from './feature-b/feature-b.module';
const app = angular
.module('app', [uirouter, common, featureA, featureB])
.config(routing);
I am starting with Angular + Flux with Webpack so may be I can help you with some things.
Basically I am installing everything with NPM, it has module export system, so it works like nothing. (You can use export-loader, but why if you do not need to.)
My webpack.config.js looks like this:
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require("html-webpack-plugin");
var nodeModulesDir = path.resolve(__dirname, './node_modules');
// Some of my dependencies that I want
// to skip from building in DEV environment
var deps = [
'angular/angular.min.js',
...
];
var config = {
context: path.resolve(__dirname, './app'),
entry: ['webpack/hot/dev-server', './main.js'],
resolve: {
alias: {}
},
output: {
path: path.resolve(__dirname, './build'),
filename: 'bundle.js'
},
// This one I am using to define test dependencies
// directly in the modules
plugins: [
new webpack.DefinePlugin({
ON_TEST: process.env.NODE_ENV === 'test'
})
],
module: {
preLoaders: [
{test: /\.coffee$/, loader: "coffeelint", exclude: [nodeModulesDir]}
],
loaders: [
{test: /\.js$/, loader: 'ng-annotate', exclude: [nodeModulesDir]},
{test: /\.coffee$/, loader: 'coffee', exclude: [nodeModulesDir]},
...
],
noParse: []
},
devtool: 'source-map'
};
if (process.env.NODE_ENV === 'production') {
config.entry = {
app: path.resolve(__dirname, './app/main.js'),
vendors: ['angular']
};
// config.output.path = path.resolve(__dirname, './dist');
config.output = {
path: path.resolve(__dirname, "./dist"),
filename: "app.[hash].js",
hash: true
};
config.plugins.push(new webpack.optimize.UglifyJsPlugin());
config.plugins.push(new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.[hash].js'));
config.plugins.push(new HtmlWebpackPlugin({
title: 'myApp',
template: path.resolve(__dirname, './app/index.html'),
inject: 'body'
}));
delete config.devtool;
}
else {
deps.forEach(function (dep) {
var depPath = path.resolve(nodeModulesDir, dep);
config.resolve.alias[dep.split(path.sep)[0]] = depPath;
config.module.noParse.push(depPath);
});
}
module.exports = config;
My main.js looks like this:
var angular = require('angular');
if(ON_TEST) {
require('angular-mocks/angular-mocks');
}
require('./index.coffee');
And index.coffee containt main angular module:
ngModule = angular.module 'myApp', []
require('./directive/example.coffee')(ngModule)

Categories