xxxgitone / webpack-skill

webpack的使用

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

webpack技能

编译es6/es7+

npm install "babel-loader@^8.0.0-beta" @babel/core @babel/preset-env webpack

配置

rules: [
  {
    // 注意别写成字符串形式,test: '/\.js$/',尴尬
    test: /\.js$/,
    // use: 'babel-loader'
    use: {
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env', {
          targets: {
            browsers: ['> 1%', 'last 2 versions', 'not ie <= 8']
          }
        }]
      }
    },
    exclude: /node_modules/
  }
]

targets.browsers表示支持的浏览器,详细列表

babel插件

使用babel-loader编译,默认只会编译语法,比如箭头函数等。但是很多api并不会进行编译,比如Generator, Set, Map, Arrayincludes方法等。需要使用插件

  • babel-polyfill: 全局编译,直接全局引用即可,适用于开发应用

安装

npm i babel-polyfill -S

使用

import 'babel-polyfill'
  • babel-runtime-transform: 局部编译,不会污染全局,适用于开发框架

安装

npm i @babel/plugin-transform-runtime -D

npm i @babel/runtime -S

使用,配置根目录下的.babelrc

{
  "presets": [
    ["@babel/preset-env", {
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      },
      "debug": true
    }]
  ],

  "plugins": [
    "@babel/plugin-transform-runtime"
  ]
}

编译typescript

安装

npm i typescript ts-loader -S

如果使用的是webpack3,ts-loader记得指定低版本的比如ts-loader@3.5.0,要不然会报错

配置webpack.config.js

rules: [
  {
    test: /\.js$/,
    use: {
      loader: 'babel-loader',
    },
    exclude: /node_modules/,      
  },
  {
    test: /\.tsx?$/,
    use: {
      loader: 'ts-loader'
    }
  }
]

根目录新建tsconfig.json文件

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "allowJs": true
  },
  "include": [
    "./src/*"
  ],
  "exclude": [
    "./node_modules"
  ]
}

typescript中使用第三方库的时候,如果需要类型判断,则需要安装第三方的类型库

比如npm i @types/lodash -D安装完成后,当使用lodash方法的时候就会有对应的类型判断功能。

提取公用代码CommonsChunkPlugin

当多个js文件引用同一个代码块,将相同的代码提取出来,这样相同的代码页面只要加载一次就可以

CommonsChunkPluginwebpack内置的一个插件,所以使用的时候要安装webapck进依赖,即npm i webapck -D

默认情况下,需要配置多个入口entry才能提取出公共模块,很多时候也需要将第三方库也打包成公共模块

配置入口项

entry: {
  // 两个页面,它们使用了相同的模块
  pageA: './src/pageA.js',
  pageB: './src/pageB.js',
  // 这是第三方模块,单独一个入口
  vendor: ['lodash', 'axios']
}

output: {
  path: path.resolve(__dirname, './dist'),
  filename: '[name].bundle.js',
  chunkFilename: '[name].chunk.js'
},

/* 省略...*/

// 配置插件
plugins: [
  // 打包第三方的库
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    minChunks: Infinity
  }),

  // 项目的业务代码
  new webpack.optimize.CommonsChunkPlugin({
    name: 'manifest',
    minChunks: Infinity
  })

  // 简写
  // new webpack.optimize.CommonsChunkPlugin({
  //   names: ['vendor', 'manifest'],
  //   minChunks: Infinity
  // })
]

当我们如果想要将业务代码和三方库代码打包到一个文件下,我们只要使用一次CommonsChunkPlugin即可

new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: Infinity
})

这样业务代码和三方库代码都会打包进入vendor.bundle.js

另外,也可以提取的页面

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'common',
    // 重复两次就提取出来
    minChunks: 2,
    chunks: ['pageA', 'pageB']
  }),
]

处理CSS

style-loader: 主要用于创建style标签的

css-loader: 主要让js能够import引入

npm i style-loader css-loader -D

配置

module: {
  rules: [
    {
      test: /.css$/,
      use: [
        {
          loader: 'style-loader'
        },
        {
          loader: 'css-loader',
          options: {
            // 开启css-modules
            // modules: true
            // 压缩
            minimize: true
          }
        }
      ]
    }
  ]
}

使用预处理器SASS

安装

npm i node-sass sass-loader -D

配置

module: {
  rules: [
    {
      test: /.scss$/,
      use: [
        {
          loader: 'style-loader'
        },
        {
          loader: 'css-loader'
        }
        {
          loader: 'sass-loader'
        }
      ]
    }
  ]
}

提取CSS插件extract-text-webpack-plugin

安装

npm i extract-text-webpack-plugin -D

配置

var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /.scss$/,
        use: ExtractTextWebpackPlugin.extract({
          fallback: {
            loader: 'style-loader'
          },
          use: [
            {
              loader: 'css-loader',
              options: {
                minimize: true
              }
            },
            {
              loader: 'sass-loader'
            }
          ]
        })
      }
    ]
  },

  plugins: [
    new ExtractTextWebpackPlugin({
      filename: '[name].min.css',
    })
  ]
}

使用postcss

处理css的工具,配置各种postcss的插件可以完成很多功能,常见的比如:

autoprefixer 添加浏览器厂商前缀

cssnano 压缩,css-loader引用的它

postcss-next 可以使用新的语法: variablescalccustom selectors

安装

npm i postcss postcss-loader autoprefixer cssnano postcss-cssnext

使用

 module: {
  rules: [
    {
      test: /.scss$/,
      use: ExtractTextWebpackPlugin.extract({
        fallback: {
          loader: 'style-loader'
        },
        use: [
          {
            loader: 'css-loader',
            options: {
              minimize: true
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: [
                // require('autoprefixer')(),
                // cssnext 包含了autoprefixer
                require('postcss-cssnext')()
              ]
            }
          },
          {
            loader: 'sass-loader'
          }
        ]
      })
    }
  ]
}

设置需要兼容的浏览器,可以统一放在package.json中,这样所有插件都会使用package.json中的浏览器配置,包括babel-loader

"browserslist": [
  "> 1%",
  "last 2 versions",
  "not ie <= 8"
]

Tree shaking

把没有用到的代码自动剔除掉,使用webpack内置插件UglifyJsPlugin可以实现,这个插件可以实现压缩以及tree shaking

plugins: [
  new webpack.optimize.UglifyJsPlugin()
]

另外需要注意的是webpack已经原生支持 ES Module,不需要 babel 把 ES Module 转换成曾经的 commonjs 模块了,需要关闭 babel 默认的模块转义,否则tree-shaking不会生效

{
  "presets": [
    ["env", {
      "modules": false
      }
    }]
  ]
}

图片处理

file-loader:处理css引用图片

url-loader: 和file-loader功能类似,但是可以将图片转换成base64

img-loader: 图片压缩

postcss-sprites: 合成雪碧图

module: {
  rules: [
    {
      test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
      use: [
        {
          loader: 'url-loader',
          options: {
            // 小于10k的图片会转成base64位的形式
            limit: 10000,
            name: 'img/[name]-[hash:5].[ext]'
            publicPath: '',
            outputPath: 'dist/',
            // 生成相对url
            useRelativePath: true
          }
        }
      ]
    },
  ]
}

处理字体

和处理图片类似

module: {
  rules: [
    {
      test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
      use: [
        {
          loader: 'url-loader',
          options: {
            limit: 10000,
            name: 'fonts/[name]-[hash:5].[ext]'
            publicPath: '',
            outputPath: 'dist/',
            useRelativePath: true
          }
        }
      ]
    },
  ]
}

使用第三方库

以使用jquery为例

如果使用cdn链接,直接放在html中使用script引入即可。

如果通过npm安装了jQuery,可以使用插件注入到全局

plugins: [
  new webpack.ProvidePlugin({
    $: 'jquery',
  })
]

这样可以在项目的各个地方直接使用$了,不同再次引入

如果jquery是我们自己下载的,放在自定义的目录下lib/jquery.js

通过resolve设置别名

resolve: {
  alias: {
    jquery$: path.resolve(__dirname, './src/lib/jquery.js')
  }
}

处理HTML文件

使用插件html-webpack-plugin让打包的cssjs自动插入到Html文件中

new HtmlWebpackPlugin({
  // 默认就是
  filename: 'index.html',
  template: './index.html',
  // 是否自动插入生成的css和js文件,默认true
  // inject: false,
  // 指定需要载入的chunks,默认载入enry所有的
  // chunks: ['app']
  // 压缩
  // minify: {
  //   collapseWhitespace: true
  // }
})

如果在模板index.html中直接使用图片,要用额外的html-loader来进行处理

module: {
  rules: [
    {
      test: /\.html$/
      use: [
        {
          loader: 'html-loader',
           options: {
            // 默认会处理`img:src`, 如果图片放在`data-`上就要重新设定
            attrs: ['img:src', 'img:data-src']
          }
        }
      ]
    }
  ]
}

搭建开发环境

搭建一个开发环境,提供一个本地服务,可以很好的模拟线上服务,减少上线后出现的问题。并且可以借助webpack提供的插件实现热更新,提升开发体验。

每次修改代码后自动实现编译打包,我们等每次打包之前,将原有的打包文件删除掉,利用clean-webpack-plugin插件

npm i clean-webpack-plugin -D

使用

plugins: [
  new CleanWebpackPlugin(['dist'])
]

webpack提供了一个强大的开发服务插件webpack-dev-server

常用配置

devServer: {
  port: 9999,
  // 默认为true,推荐使用默认值
  // inline: false,
  // 开发的单页面的时候用,当访问到不存在的页面时会出现404
  // 设置后会统一跳转到index.html
  historyApiFallback: true,
  // 代理远程接口,使用的是`http-proxy-middleware` https://github.com/chimurai/http-proxy-middleware
  proxy: {
    // 代理地址
    '/api': {
      // 目标地址
      target: 'https://www.example.com',
      //// 跨域
      changeOrigin: true
      // 代理请求头
      // headers:
      // log日志
      // logLevel
    },
  },
}

开启source map调试

source map的值有很多,推荐使用

开发阶段

devtool: 'cheap-module-eval-source-map'

生产环境

devtool: '#source-map'

eslint

安装 npm i eslint eslint-loader eslint-config-standard eslint-friendly-formatter eslint-plugin-import eslint-plugin-node eslint-plugin-promise eslint-plugin-standard -D

配置

module: {
  rules: [
    {
      test: /\.js$/,
      use: [
        {
          loader: 'babel-loader',
        },
        {
          loader: 'eslint-loader',
          options: {
            formatter: require('eslint-friendly-formatter')
          }
        }
      ]
    },
  ]
}

.eslintrc.js配置

module.exports = {
  root: true,
  extends: 'standard',
  plugins: [
    // 在html文件中写js会有检测
    // 'html'
  ],
  env: {
    browser: true,
    node: true
  },
  rules: {
  }
}

webpack打包速度优化

速度影响因素: 文件多,依赖多,页面多!

第三方代码和业务代码分离(vendor和app)

在我们项目中经常会用到许多的三方库,比如vue,elementui,axios等,我们修改自己的业务代码,进行打包,发现每次这些第三方库也会一起再打包一次.其实三方库我们基本不会去变动它,除非进行升级之类的操作,每次都打包它们,显然有些浪费时间.

使用Dll插件可以解决这个问题,Dll是webpack的内置插件,其原理借鉴了windows系统的dll,一个单纯的依赖包,供你开发引用.

使用dll打包,先需要编写单独的配置文件,专门用来打包这些三方库,三方库打包出来以后会有其索引,并放在manifest.js文件中,然后在打包业务代码的时候,只需要引用对应的manifest.json文件就可以了.

对应的webpack.dll.config.js文件配置信息

const path = require('path')
const webpack = require('webpack')

const vendors = [
  'vue',
  'vue-router',
  'vuex',
  'axios',
  'element-ui'
]

module.exports = {
  entry: {
    vendor: vendors
  }
  output: {
    path: path.join(__dirname, '../src/dll/'),
    filename: '[name].dll.js',
    library: '[name]'
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, '../src/dll/', '[name]-manifest.json'),
      name: '[name]' // name是dll暴露的对象名,跟output.library保持一致
    }),
    new webpack.optimize.UglifyJsPlugin()
  ]
}

然后在业务代码打包的配置文件中配置引用

new webpack.DllReferencePlugin({
  manifest: require('../src/dll/ui-manifest.json')
})

优化UglifyJsPlugin

webpack打包默认为链式,使用parallel可以让打包并行,多个loader共同工作,节约时间

new UglifyJsPlugin({
  parallel: true,
  cache: true // 开启缓存
})

sourcemap

也可以将sourcemap关掉,缺点就是当线上代码有问题的时候,不好调试

长缓存优化

什么是长缓存

About

webpack的使用


Languages

Language:JavaScript 88.3%Language:Vue 7.0%Language:HTML 3.3%Language:CSS 0.8%Language:TypeScript 0.6%