概念
webpack 是一个模块打包机, 它可以将我们项目中的所有 JS, 图片, CSS 等资源, 根据其入口文件的依赖关系, 打包成一个能被浏览器识别的 JS 文件. 能够帮助前端开发将打包的过程更智能化和自动化.
WebPack 和 Grunt 以及 Gulp 相比有什么特性
Webpack 和另外两个并没有太多的可比性, Gulp/Grunt 是一种能够优化前端的开发流程的工具, 而 WebPack 是一种模块化的解决方案, 不过 Webpack 的优点使得 Webpack 在很多场景下可以替代 Gulp/Grunt 类的工具.
开始使用
安装 webpack, 目前 webpack 已更新到 4.x 版本, 且大力度宣传的是 cli 方式启动, 更推崇的是让开发者使用高度封装的 cli. 基于此, 我们应该安装 webpack^4.1.1,webpack-cli^2.0.10(想要执行 webpack 的命令必须有这个包),webpack-dev-server^3.1.0.
webpack 的 mode
webpack4 的 mode 给出了两种配置: development 和 production. 生产模式下, 启用了 代码压缩, 作用域提升(scope hoisting), tree-shaking, 使代码最精简; 开发模式下, 相较于更小体积的代码, 提供的是打包速度上的优化. 所以, 我们一般配置 2 个文件, webpack.dev.conf.JS 和 webpack.prod.conf.JS. 修改 package.JSON 里面的 scripts:
- "scripts": {
- "dev": "webpack --mode development",
- "build": "webpack --mode production"
- }
按项目搭建诉求加入配置
一般诉求:
JS 的处理: 转换 ES6 代码, 解决浏览器兼容问题
CSS 的处理: 编译 CSS, 自动添加前缀, 抽取 CSS 到独立文件
html 的处理: 复制并压缩 HTML 文件
dist 的清理: 打包前清理源目录文件
assets 的处理: 静态资源处理
server 的启用: development 模式下启动服务器并实时刷新
- source-map
- eslint
1. 转换 JS, 解决兼容性问题, 用 babel 转换 ES6 代码, 用 babel 转换 ES6 代码需要使用到 babel-loader, 我们需要安装一系列的依赖:
NPM i babel-core babel-loader babel-preset-env --save-dev
然后在根目录新建一个 babel 配置文件. babelrc:
- {
- "presets": [
- [
- "@babel/preset-env",
- {
- "targets": {
- "browsers": [
- "last 2 iOS major versions",
- "last 2 Android major versions"
- ],
- "ios":"8.2"
- },
- "exclude":["es6.promise"],
- "useBuiltIns": "usage",
- "debug": true
- }
- ]
- ],
- "plugins": ["@babel/transform-runtime"]
- }
Babel 默认只转换新的 JavaScript 语法, 而不转换新的 API. 例如, Iterator,Generator,Set,Maps,Proxy,Reflect,Symbol,Promise 等全局对象, 以及一些定义在全局对象上的方法 (比如 Object.assign) 都不会转译. 如果想使用这些新的对象和方法, 则需要为当前环境提供一个 polyfill.
解决方案一:
引入 babel-polyfill, 它会 "加载整个 polyfill 库", 针对编译的代码中新的 API 进行处理, 并且在代码中插入一些帮助函数.
解决方案二:
babel-runtime
两种方案区别:
babel-polyfill 解决了 Babel 不转换新 API 的问题, 但是直接在代码中插入帮助函数, 会导致污染了全局环境, 并且不同的代码文件中包含重复的代码, 导致编译后的代码体积变大. babel-runtime 配置了之后, 打包时会 "按需加载", 当用到某个 polifill 时再引入对应的垫子, 这样可以减少体积. 但在某些情况下仍然不能被 babel-runtime 替代, 例如, 代码:[1, 2, 3].includes(3),Object.assign({}, {key: 'value'}),Array,Object 以及其他 "实例" 下 es6 的方法, babel-runtime 是无法支持的, 因为 babel-runtime 只支持到 static 的方法.
因此, babel-runtime 适合在组件, 类库项目中使用, 而 babel-polyfill 适合在业务项目中使用.
babel-runtime 版本搭配注意:
- // 安装 babel-runtime 和 babel-plugin-transform-runtime, 配置如下:
- {
- "plugins": ["transform-runtime"]
- }
- // 高版本的 babel, 安装 @babel/plugin-transform-runtime,@babel/runtime
- {
- "plugins": ["@babel/transform-runtime"]
- }
2. 转换 CSS
相关的 loder:Less-loader,postcss-loader,CSS-loader,style-loader 等. 利用 mini-CSS-extract-plugin 来打包到一个文件里面. 参考代码:
- const MiniCssExtractPlugin = require("mini-css-extract-plugin");
- module.exports = (env, argv) => {
- const devMode = argv.mode !== 'production'
- return {
- module: {
- rules: [
- {
- test: /\.CSS$/,
- use: [
- devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
- 'css-loader',
- 'postcss-loader'
- ]
- },
- ]
- },
- plugins: [
- new MiniCssExtractPlugin({
- filename: "[name].css",
- chunkFilename: "[id].css"
- })
- ]
- }
- }
3. 处理 HTML 文件, 一般用 HTML-webpack-plugin, 参考代码:
- const HtmlWebPackPlugin = require("html-webpack-plugin");
- module.exports = {
- module: {
- rules: [
- {
- test: /\.HTML$/,
- use: [{
- loader: "html-loader",
- options: {
- minimize: true
- }
- }]
- }
- ]
- },
- plugins: [
- new HtmlWebPackPlugin({
- template: "./src/index.html",
- filename: "./index.html"
- })
- ]
- };
更多配置解释, 参考 https://segmentfault.com/a/1190000007294861
4. 清理
每次打包, 都会生成项目的静态资源, 随着某些文件的增删, 我们的 dist 目录下可能产生一些不再使用的静态资源, webpack 并不会自动判断哪些是需要的资源, 为了不让这些旧文件也部署到生产环境上占用空间, 所以在 webpack 打包前最好能清理 dist 目录.
- const CleanWebpackPlugin = require('clean-webpack-plugin');
- module.exports = {
- plugins: [
- new CleanWebpackPlugin(['dist']),
- ]
- };
5. 资源处理
- {
- test: /\.HTML$/,
- loader: 'art-template-loader',
- }, {
- test: /\.jpg$/,
- loader: 'url-loader?mimetype=image/jpg'
- }, {
- test: /\.PNG$/,
- loader: 'url-loader?mimetype=image/png'
- },
- {
- test: /\.svg/,
- loader: 'url-loader?mimetype=image/svg+xml'
- }
6.server 的启用
- "scripts": {
- "start": "webpack-dev-server --mode development --open",
- "build": "webpack --mode production"
- }
7. 开启 source-map
- devtool: "inline-source-map" // 详细到打包前的每个没被压缩的文件
- or
- devtool: "source-map" // 打包后的未压缩文件
8. 配置 eslint
8.1 要使 webpack 支持 eslint, 就要要安装 eslint-loader.
- {
- test: /\.JS$/,
- loader: 'eslint-loader',
- enforce: "pre",
- include: [path.resolve(__dirname, 'src')], // 指定检查的目录
- options: { // 这里的配置项参数将会被传递到 eslint 的 CLIEngine
- formatter: require('eslint-friendly-formatter') // 指定错误报告的格式规范, formatter 默认是 stylish, 如果想用第三方的要另外安装
- }
- }
8.2 安装 eslint, 创建配置文件 '.eslintrc.js'
- module.exports = {
- 'root': true,
- 'plugins': [
- 'html'
- ],
- 'settings': {
- 'html/html-extensions': ['.wxml']
- },
- 'rules': {
- 'newline-per-chained-call': 'off',
- 'eqeqeq': 'off',
- 'indent': ['error', 4, { SwitchCase: 1 }],
- 'prefer-rest-params': 'off',
- 'prefer-template': 'off',
- 'array-callback-return': 'off', // 暂时关闭
- 'prefer-const': 'warn',
- 'no-restricted-properties': [2, {
- 'object': 'wx',
- 'property': 'navigateTo',
- 'message': 'Please use this.$goto!!!'
- }]
- }
- }
参考资料: https://segmentfault.com/a/1190000012936029#articleHeader2
更多详细细节看文档: http://eslint.cn/docs/user-guide
production 相关的一些配置
1, 代码压缩, uglifyjs-webpack-plugin
- new UglifyJsPlugin({
- test: /.JS$|.jsx$/i,
- uglifyOptions: {
- compress: {
- pure_funcs: ['console.log', 'alert']
- },
- },
- })
2. 提取公共模块
- output: {
- ...
- chunkFilename: '[name].[chunkhash:8].js'
- },
- ...
- optimization: {
- splitChunks: {
- cacheGroups: {
- vendor: {
- test: /[\\/]node_modules[\\/]/,
- name: 'common',
- chunks: 'all'
- }
- }
- }
- }
来源: http://www.bubuko.com/infodetail-2883341.html