webpack.config

常用的 webpack 插件

webpack 兼容 ie8 问题

plugins: [
  /** [uglify#1179](https://github.com/mishoo/UglifyJS2/pull/1179)
   * [Webpack构建兼容IE8](https://segmentfault.com/a/1190000007699918?winzoom=1)
   */
  new webpack.optimize.UglifyJsPlugin({
    compress: { screw_ie8: false },
    mangle: false,
    output: { screw_ie8: false },
  }),
]

使用 webpack 打包后,代码没有兼容问题;uglifyjs压缩后才会不兼容 ie8。因此在压缩时配置兼容 ie8;

如何在 webpack 中引入未模块化的库,如 Zepto

// webpack.config
{
  // ...
  module: {
    loaders: [
      {
        test: require.resolve('zepto'),
        loader: 'exports-loader?window.Zepto!script-loader',
      },
    ]
  }
}

这样我们在页面入口文件中就可以这么写:

// entry.js
import $ from 'zepto'

$(function () {
  // ...
})

tree-shaking

为了学会使用 tree shaking,你必须……

  • 使用 ES2015 模块语法(即 import 和 export)。
  • 引入一个能够删除未引用代码(dead code)的压缩工具(minifier)(例如 UglifyJSPlugin)。

vue webpack 项目配置

a demo config file:

const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const Jarvis = require('webpack-jarvis')
const merge = require('webpack-merge')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

let base = {
  entry: {
    index: './src/index.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist/'),
    filename: 'js/[name].js'
  },
  resolve: {
    extensions: ['.js', '.vue'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
      vue$: 'vue/dist/vue.common.js'
    }
  },
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.(js|vue)$/, // to lint .vue files, also need to config .eslintrc.js
        exclude: /node_modules/,
        use: [
          {
            loader: 'eslint-loader',
            options: {
              formatter: require('eslint-friendly-formatter'),
              fix: true, // eslint --fix
              failOnError: true
            }
          }
        ]
      },
      {
        test: /\.vue$/,
        use: [
          {
            loader: 'vue-loader',
            options: {
              loaders: {
                js: 'babel-loader!eslint-loader'
              }
            }
          }
        ]
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader'
        })
      },
      {
        test: /\.(png|jp(e)?g|gif|svg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
              name: 'image/[name].[ext]'
            }
          }
        ]
      }, {
        test: /.html$/,
        use: [{
          loader: 'html-loader',
          options: {
            minimize: true
          }
        }]
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('css/style.css'),
    new OptimizeCSSPlugin({
      cssProcessorOptions: {
        assetNameRegExp: /\.optimize\.css$/g,
        cssProcessor: require('cssnano'),
        cssProcessorOptions: { discardComments: { removeAll: true } },
        canPrint: true
      }
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, './node_modules')
          ) === 0
        )
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      chunks: ['vendor']
    }),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: './src/index.html',
      chunksSortMode: 'dependency',
      hash: true,
      cache: true
    })
  ]
}

if (process.env.NODE_ENV === 'dev') {
  base = merge(base, {
    plugins: [
      devServer: {
        contentBase: path.join(__dirname, 'src'),
        // host: '0.0.0.0',
        port: 80,
        compress: false
      },
      new webpack.DefinePlugin({
        DEV: true
      }),
      // A very intelligent browser based Webpack dashboard
      new Jarvis({
        port: 1337 // optional: set a port
      })
    ]
  })
}

if (process.env.NODE_ENV === 'production') {
  base = merge(base, {
    plugins: [
      // spa add favicon
      new CopyWebpackPlugin([
        {
          from: 'src/favicon.ico'
        }
      ]),
      new UglifyJsPlugin({
        uglifyOptions: {
          compress: {
            drop_console: true
          }
        }
      })
    ]
  })
}

module.exports = base

打包后生产的目录结构如下:

├── dist
|   ├── css/
|   ├── image/
|   └── js/
|   └── index.html
|   └── favicon.ico

.eslintrc.js: lint .js and .vue files

module.exports = {
  root: true,
  env: {
    es6: true,
    browser: true,
  },
  parserOptions: {
    parser: 'babel-eslint',
    sourceType: 'module',
  },
  // more configs see https://github.com/vuejs/eslint-plugin-vue#user-content-gear-configs
  extends: ['plugin:vue/base', 'standard'],
  plugins: ['vue'],
}

add favicon to spa

1.use copy-webpack-plugin

// spa add favicon
new CopyWebpackPlugin([
  {
    from: 'favicon.ico',
    to: 'dest'
  }
]),

2.use native javascript

in your main.js

// add favicon
const favicon = require('./images/favicon.png')
let link =
  window.document.querySelector('link[rel*="icon"]') ||
  document.createElement('link')
link.type = 'image/x-icon'
link.rel = 'shortcut icon'
link.href = favicon
window.document.getElementsByTagName('head')[0].appendChild(link)