I have a webpack config that is based off https://github.com/vuejs-templates/webpack-simple/blob/master/template/webpack.config.js
It uses vue-loader and babel-loader. The issue is I cannot get it to generate ES5 code so that it will work in the most broad range of clients.
If I use the ES2015 preset, webpack.optimize.UglifyJsPlugin fails to minify the output because Uglify can only handle ES5 (not counting the harmony branch). The errors are similar to: Unexpected token: punc (() and occur in multiple files.
I can work around this by using babili-webpack-plugin which will minify the ES6 code but is very slow. However, when I deploy this code, I see errors being reported back saying Block-scoped declarations (let, const, function, class) not yet supported outside strict mode so I know they are older clients choking on ES6 code.
How can I get proper ES5 code output from babel-loader? I have tried multiple presets, with or without the transform-runtime plugin. Config below:
const webpack = require('webpack');
const globEntries = require('webpack-glob-entries');
const _ = require('lodash');
const path = require('path');
const BabiliPlugin = require("babili-webpack-plugin");
const env = process.env.NODE_ENV;
let entries;
if (env === 'production') {
entries = globEntries('./src/**/vue/*.js');
} else {
entries = _.mapValues(globEntries('./src/**/vue/*.js'), entry => [entry, 'webpack-hot-middleware/client?reload=true']);
}
module.exports = {
entry: entries,
output: {
path: '/', ///no real path is required, just pass "/"
publicPath: '/vue',
filename: '[name].js',
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
scss: 'vue-style-loader!css-loader!sass-loader',
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
},
// other vue-loader options go here
},
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
query: {
presets: ['es2015'],
plugins: ['transform-runtime'],
},
},
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]',
},
},
],
},
resolve: {
alias: {
vue$: 'vue/dist/vue.esm.js',
},
},
plugins: [
new webpack.HotModuleReplacementPlugin(), // Enable HMR
new webpack.NoEmitOnErrorsPlugin(),
],
performance: {
hints: false,
},
devtool: '#eval-source-map',
};
if (env === 'staging' || env === 'production') {
//module.exports.devtool = env === 'staging' ? '#source-map' : false;
module.exports.devtool = '#source-map';
module.exports.output.path = path.resolve(__dirname, './src/v1/parse/cloud/public/vue');
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: `"${env}"`,
},
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false,
},
}),
// new BabiliPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: true,
}),
]);
}
vue-loader will process your js with babel-loader (if it's detected), and uses .babelrc by default.
In your current setup you are not passing any options to Babel when it is used by vue-loader (meaning Babel uses no rules for your Vue files).
Either create .babelrc or specify the js loader by yourself for the .vue files to provide it with options:
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
js: 'babel?presets[]=es2015' // Pass parameters as options
}
}
}
The env preset for Babel has an uglify option that will fully compile to ES5. This preset is recommended practice to keep your environment up to date.
// .babelrc
{
"presets": [
[ "env", { "uglify": true } ],
"stage-1" // Or other presets not included with 'env' preset.
],
"plugins": ["transform-runtime"]
}
Instead of using preset es2015 only, you might add es2016 and es2017, as well as stage-4, stage-3, etc. to assure all your code is transformed, and not just the ES2015 parts.
Nothing wrong with answer here already, but here is a solution that does not require a .babelrc file. This answer works for a standalone webpack.config.js file. I got this answer from taking a look under the hood of the laravel-mix library.
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders:{
js: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
['env', {
'modules': false,
'targets': {
'browsers': ['> 2%'],
uglify: true
}
}]
],
plugins: [
'transform-object-rest-spread',
['transform-runtime', {
'polyfill': false,
'helpers': false
}]
]
}
},
}
}
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
I spent the better part of a day reading up all these useless blogs omit the core concept that babel-loader has to be attached to the vue-loader.
Related
The existing configuration for compilation seems to have issues compiling some syntax used in sentry source code. The screenshot shows two places where the exception occurs.
Here is the configuration used
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const appDirectory = path.resolve(__dirname, '../')
// This is needed for webpack to compile JavaScript.
// Many OSS React Native packages are not compiled to ES5 before being
// published. If you depend on uncompiled packages they may cause webpack build
// errors. To fix this webpack can be configured to compile to the necessary
// `node_module`.
const babelLoaderConfiguration = {
test: /\.js$/,
// Add every directory that needs to be compiled by Babel during the build.
include: [
path.resolve(appDirectory, 'index.web.js'),
path.resolve(appDirectory, 'src'),
path.resolve(appDirectory, 'prebundled'),
path.resolve(appDirectory, 'node_modules/react-native')
],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
// The 'metro-react-native-babel-preset' preset is recommended to match React Native's packager
presets: ['module:metro-react-native-babel-preset'],
// Re-write paths to import only the modules needed by the app
plugins: [
'react-native-web',
[
'module-resolver',
{
alias: {
'^react-native$': 'react-native-web'
}
}
]
]
}
}
}
// This is needed for webpack to import static images in JavaScript files.
const imageLoaderConfiguration = {
test: /\.(gif|jpe?g|png|svg)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
esModule: false
}
}
}
module.exports = {
entry: [
// load any web API polyfills
// path.resolve(appDirectory, 'polyfills-web.js'),
// your web-specific entry file
path.resolve(appDirectory, 'index.web.js')
],
output: {
filename: '[name].[contenthash].js',
publicPath: '/',
path: path.resolve(appDirectory, 'dist')
},
module: {
rules: [
babelLoaderConfiguration,
imageLoaderConfiguration,
{
test: /\.tsx?$/,
loader: 'ts-loader',
// exclude: /node_modules/,
options: {
configFile: 'tsconfig.web.json',
transpileOnly: true
}
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new CleanWebpackPlugin(),
new webpack.IgnorePlugin({
resourceRegExp: /react-native-screens/
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, './index.html')
}),
new CopyPlugin({
patterns: [
{
context: __dirname,
from: './images/**/*',
to: '[path][name][ext]',
force: true
},
{ from: path.join(__dirname, './main.css'), to: './main.css' },
{
from: path.join(__dirname, './.well-known/apple-app-site-association'),
to: './.well-known/'
}
]
}),
new webpack.HotModuleReplacementPlugin()
],
resolve: {
alias: {
'react-native$': 'react-native-web',
'react-native-maps$': 'react-native-web-maps'
},
extensions: ['.web.tsx', '.web.ts', '.tsx', '.ts', '.web.js', '.js', '.json']
}
}
I tried implementing something that looks like showing in this documentation but it did not help.
https://docs.sentry.io/platforms/javascript/guides/react/sourcemaps/uploading/webpack/
You need to add #sentry/react-native to compile.
Update you webpack config like this:
...
const compileNodeModules = [
'#sentry/react-native'
]
const babelLoaderConfiguration = {
...
...compileNodeModules
}
I have a Chrome Extension where I started using webpack. I can build it just fine, but in development mode when I am run npm run watch after the first recompilation is triggered the index.html disappears from the build directory.
Here is script part of my package.json:
"build": "node utils/build.js",
"watch": "webpack --watch & webpack-dev-server --inline --progress --colors"
}
My webpack.config.js: (I have a bunch of content scripts listed as separate entry point as well that I omitted)
path = require("path"),
env = require("./utils/env"),
CleanWebpackPlugin = require("clean-webpack-plugin").CleanWebpackPlugin,
CopyWebpackPlugin = require("copy-webpack-plugin"),
HtmlWebpackPlugin = require("html-webpack-plugin"),
WriteFilePlugin = require("write-file-webpack-plugin"),
MiniCssExtractPlugin = require('mini-css-extract-plugin');
const fileExtensions = ["jpg", "jpeg", "png", "gif", "eot", "otf", "svg", "ttf", "woff", "woff2"];
const options = {
mode: process.env.NODE_ENV || "development",
entry: {
// the single js bundle used by the single page that is used for the popup, options and bookmarks
index: path.join(__dirname, "src", "", "index.js"),
// background scripts
"js/backgroundScripts/background": path.join(__dirname, "src", "js/backgroundScripts", "background.js"),
"js/backgroundScripts/messaging": path.join(__dirname, "src", "js/backgroundScripts", "messaging.js")
},
output: {
publicPath: '',
path: path.join(__dirname, "build"),
filename: "[name].bundle.js"
},
module: {
rules: [
{
enforce: "pre",
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
options: {
cache: true,
emitWarning: true
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: true,
},
},
'css-loader',
'sass-loader',
],
},
{
test: new RegExp('\.(' + fileExtensions.join('|') + ')$'),
loader: "file-loader?name=[name].[ext]",
exclude: /node_modules/
},
{
test: /\.html$/,
loader: "html-loader",
exclude: /node_modules/
},
{
test: /\.(js|jsx)$/,
loader: "babel-loader",
exclude: /node_modules/
},
]
},
resolve: {
modules: [path.resolve(__dirname, './src'), 'node_modules'],
extensions: fileExtensions.map(extension => ("." + extension)).concat([".jsx", ".js", ".css"])
},
plugins: [
// clean the build folder
new CleanWebpackPlugin(),
// expose and write the allowed env vars on the compiled bundle
new webpack.EnvironmentPlugin({
NODE_ENV: 'development', // use 'development' unless process.env.NODE_ENV is defined
DEBUG: false
}),
// copies assets that don't need bundling
new CopyWebpackPlugin([
"src/manifest.json",
{
from: "src/css",
to: 'css/'
},
{
from: "src/_locales",
to: '_locales/'
},
{
from: "src/images",
to: 'images/'
}
], { copyUnmodified: true }),
new HtmlWebpackPlugin({
template: path.join(__dirname, "src", "index.html"),
filename: "index.html",
chunks: ["index"]
}),
new WriteFilePlugin(),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
devServer: {
writeToDisk: true,
contentBase: path.join(__dirname, "../build")
}
};
if (env.NODE_ENV === "development") {
options.devtool = "cheap-module-source-map";
}
module.exports = options;
I can see index.html listed in the initial build log, but not any of the ones after that.
I would appreciate any clues of why this is is happening and how I could fix it. Thanks.
In the plugins section, you should put this line conditional only for production environment:
new CleanWebpackPlugin()
As it's role is to clean the build folder.
I generate a default project with vue-cli:
vue init webpack-simple grid-prototype
I install FontAwesome through npm:
npm install --save fontawesome
After that, I include it into main.js with:
import 'font-awesome/css/font-awesome.css'
I execute the app with:
npm run dev
And I get this error:
Failed to compile.
./node_modules/font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0
Module parse failed: Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
# ./node_modules/css-loader!./node_modules/font-awesome/css/font-awesome.css 7:684-735
# ./node_modules/font-awesome/css/font-awesome.css
# ./src/main.js
# multi (webpack)-dev-server/client?http://localhost:8082 webpack/hot/dev-server ./src/main.js
Here's my webpack.config.js (it's the default one created by the cli):
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "./dist"),
publicPath: "/dist/",
filename: "build.js"
},
module: {
rules: [
{
test: /\.css$/,
use: ["vue-style-loader", "css-loader"]
},
{
test: /\.vue$/,
loader: "vue-loader",
options: {
loaders: {}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: "file-loader",
options: {
name: "[name].[ext]?[hash]"
}
}
]
},
resolve: {
alias: {
vue$: "vue/dist/vue.esm.js"
},
extensions: ["*", ".js", ".vue", ".json"]
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: "#eval-source-map"
};
if (process.env.NODE_ENV === "production") {
module.exports.devtool = "#source-map";
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
]);
}
What am I doing wrong?
webpack-simple is suitable for quick prototyping and it doesn't have advanced rules.
Solution #1: Use webpack template instead of webpack-simple to avoid this and other issues in the future.
Solution #2: Use FontAwesome from CDN, for example:
https://www.bootstrapcdn.com/fontawesome/
I mean, just add the CDN css to your index.html
Solution #3: Add one more rule to your webpack config
module: {
rules: [
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
As it is in the webpack template:
https://github.com/vuejs-templates/webpack/blob/develop/template/build/webpack.base.conf.js
So I was checking out the realworld implementation of Sapper/Svelte: https://github.com/sveltejs/realworld
I've read a lot about SASS preprocessing, and it doesn't seem like it is fully supported, but there are some docs on it. From what I could put together, I should be able to preprocess my tags after I made the following modifications to my webpack.client.config.js file:
const svelte = require('rollup-plugin-svelte');
const sass = require('svelte-preprocess-sass').sass;
const config = require('sapper/webpack/config.js');
const webpack = require('webpack');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: config.client.entry(),
output: config.client.output(),
resolve: {
extensions: ['.js', '.html']
},
module: {
rules: [
{
test: /\.html$/,
exclude: /node_modules/,
use: {
loader: 'svelte-loader',
options: {
hydratable: true,
emitCss: !config.dev,
cascade: false,
store: true
}
}
},
config.dev && {
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" }
]
},
!config.dev && {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{ loader: 'css-loader', options: { sourceMap: config.dev } }]
})
}
].filter(Boolean)
},
plugins: [
svelte({
preprocess: {
style: sass(),
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'main',
async: true,
children: true
}),
config.dev && new webpack.HotModuleReplacementPlugin(),
!config.dev && new ExtractTextPlugin('main.css'),
!config.dev && new webpack.optimize.ModuleConcatenationPlugin(),
!config.dev && new UglifyJSPlugin(),
].filter(Boolean),
devtool: config.dev ? 'inline-source-map' : false
};
I keep getting the following error:
node server.js
realworldsapper/node_modules/tapable/lib/Tapable.js:375
arguments[i].apply(this);
Any ideas on how to fix this?
You're mixing and matching Rollup and webpack, which are two different module bundlers — you're adding rollup-plugin-svelte to a webpack config, and webpack doesn't know what to do with it so it throws an error.
Instead, use svelte-preprocess-sass inside the svelte-loader config:
use: {
loader: 'svelte-loader',
options: {
hydratable: true,
emitCss: !config.dev,
cascade: false,
store: true,
style: sass()
}
}
(Note that the style: sass() line will become preprocess: { style: sass() } in a future version of svelte-loader — see this issue).
By the way, it looks like you're using an older version of Sapper — there have been some major improvements recently, so it's worth upgrading to 0.9. Unfortunately it does mean making some changes to your project structure (see the migration guide for the details, or reclone sapper-template and copy your routes folder over).
You should add exclude: /node_modules/ to each of your rules:
test: /\.css$/,
exclude: /node_modules/, // <- Add this
This ensures that transpilation is not applied to any of the files in the node_modules folder.
I use webpack.optimize.CommonsChunkPlugin to Generate an extra chunk(vueCommon.js) which contains vuejs、vue-router、vue-resource...;but I want to Generate another business commonChunk like util.js。they are used just in some pages by "import ajax from '../service/service.js'";
problems after build:
every generated page.js has the code of service.js。
brief demos:
https://github.com/wxungang/vueJs
//webpack.base.js
"use strict";
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
const CONFIG = require('./config');
var projectRoot = CONFIG.projectRoot || path.resolve(__dirname, '../');
var _ENV = CONFIG.env || 'dev';//prod
module.exports = {
devtool: _ENV != 'prod' ? '#eval-source-map' : false,
context: __dirname,//http://wxungang.github.io/1104/vue
entry: {
app: path.join(projectRoot, './vue/app.js'),
page: path.join(projectRoot, './vue/page.js')
},
output: {
path: path.join(projectRoot, './build/vue-' + _ENV),
publicPath: '',//'./build/vue-'+_ENV+'/',//path.join(__dirname, '../src/build/dev/')
filename: '[name].js',
chunkFilename: 'chunks/[name].chunk.js',
// crossOriginLoading: 'anonymous'
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js',
'vue-router$': 'vue-router/dist/vue-router.common.js'
},
modules: ["node_modules"],
mainFiles: ["index", "app"],
extensions: [".js", ".json", '.vue']
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this nessessary.
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
'less': 'vue-style-loader!css-loader!less-loader'
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader"
},
{
test: /\.scss$/,
loaders: ["style-loader", "css-loader", "sass-loader"]
},
{
test: /\.json$/,
loader: 'json-loader'
},
{
test: /\.html$/,
loader: 'vue-html-loader'
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
plugins: [
//注入一些全局变量
new webpack.DefinePlugin({
_ENV_: _ENV,
_VERSION_: JSON.stringify("1.0.0")
}),
new webpack.optimize.CommonsChunkPlugin({
name: "commons",
// (the commons chunk name)
filename: "vueCommons.js",
// (the filename of the commons chunk)
// minChunks: 2,
// (Modules must be shared between 3 entries)
// chunks: ["pageA", "pageB"],
// (Only use these entries)
// children: true,
// async: true,
}),
//可以和entry文件联合配置
new HtmlWebpackPlugin({
inject: false,
title: 'vueJs of app',
filename: 'app.html',
template: '../vue/entry/template.ejs',
scripts: ['./vueCommons.js', './app.js']
}),
new HtmlWebpackPlugin({
inject: false,
title: 'vueJs of page',
filename: 'page.html',
template: '../vue/entry/template.ejs',
scripts: ['./vueCommons.js', './page.js']
})
]
};
How did you use CommonsChunkPlugin to generate vueCommon.js?
A simple way is to add a new wepack entry like
utils: ['../service/service.js']
then add a new CommonsChunkPlugin instance in the webpack plugins array like this
new webpack.optimize.CommonsChunkPlugin('utils'),
the CommonsChunkPlugin will do the work by remove all utils module in other chunk files and generate only one utils.js.
Or you can just set minChunks option of the existing CommonsChunkPlugin into a number to wrap the vue file and utils together.