【你应该掌握的】webpack4介绍&配置项详解

skFeTeam  本文做者:李键css

引言

做为一名前端开发,按时按质实现业务需求只是基础条件,了解一些webpack相关的配置,除了可以帮助咱们提高一下本身的技术能力(不局限于知足业务需求),也可以帮助咱们更好的维护项目、搭建适合本身团队的web站点。html

但愿经过本文能让你们对webpack4的相关配置项有一个直观的了解,以例子的形式帮助你们更好&更快的掌握相关知识点。前端

webpack4介绍

  • webpack是一个JS应用打包器,它将应用中的各个模块打成一个或者多个bundle文件。借助loaders和plugins,它能够改变、压缩和优化各类各样的文件。它的输入是不一样的资源,好比:js、css、图片、字体和html文件等等,而后将它们输出成浏览器能够正常解析的文件。
  • 2018.8.25,正式发布webpack4,相比于webpack3,带来不少的新特性更新和改善,让webpack配置更加简单
  • webppack4是目前比较主流打包工具之一,跟其余的打包工具相比,好比gulp,rollup等,webpack4优点:社区活跃度高,使用的人多,官方更新迭代快速。

webpack4配置项

准备工做

  • 安装node,webpack,而后新建文件夹–npm初始化
//webpack安装通常是不-g全局安装的,由于同时会进行好几个项目,有时候这几个项目的webpack版本都是不同的,所以都是根据项目来局部安装,只在独立的项目中有效。
npm install webpack-cli webpack --save-dev 
//能够一路回车,初始化(项目名字,版本号,描述等默认就好,须要更改的能够在package.json文件中更改)
npm init/npm init -y 
复制代码

mode属性

  • mode属性能够设置为:development(代码不压缩)/production(代码压缩),在开发模式的时候能够提供更加详细的错误日志和提示,在生产环境打包的时候能够webpack专一项目的打包,去除掉开发阶段的运行的代码,是打包的生产环境的包文件更小。

entry/output

  • 入口和打包成功的出口–基本配置
//webpack打包的时候会默认找webpack.config.js文件
//使用path,首先须要引入
const path = require('path')
module.exports = {
    mode: 'development',//开发模式
    entry: './index.js',//指定入口文件
    output: {
        filename: 'bundle.js',//给成功打包的文件定义名字
        path: path.resolve(__dirname,'dist'),//__dirname--相对webpack.config.js这个文件同级根目录,生成的打包文件dist目录下面
    }
}
entry: {
    main: './src/index',
    sub: './src/index'
}
output: {
    publicPath: ''---若是须要加域名的话能够这样配置
    filename: '[name].js',---name占位符对应着entry中的key值
    path: resolve.path(__dirname,'dist')
}
复制代码
  • 代码演示—1
npx webpack -v
npx webpack index.js
//在package.js的script能够配置运行打包命令
"script": {
    "build": "webpack"
}
npm run build
复制代码
  • 代码运行成功后–package.json中的默认配置,npm webpack index.js成功后生成后,Hash–惟一的hash值,version–webpack版本,Time–打包耗费的时间,built中,asset–打包后的文件,size–打包文件的大小,chunks–每一个打包文件对应的id值,chunk Names–打包文件名,main–对应着打包入口文件

img

img

img

loader

  • 什么是loader,webpack对不是js后缀的文件是不能进行处理的,这时候须要借助loader,loader其实就是一个打包方案,webpack对不是js后缀的文件不知道怎么去打包,可是loader是知道的,因此这时候webpack就要依赖loader来执行打包文件。
  • file-loader 图片/字体文件打包loader,这时候须要在webpack.config.js中增长图片/字体打包规则
//webpack.config.js
module.exports = {
    ...
    module: {
    //规则数组类型--有不少不一样类型的打包规则
        rules: [
            {
                test: /\.(jpg|png|jpeg)$/,
                use: {
                    loader: 'file-loader',
                    options: {
                    //placehold--占位符 name--文件名,hash--hash值,ext-文件后缀名
                        name: '[name]_[hash].[ext]',
                        //回把图片打包到dist目录下image文件夹里
                        outputPath: "./image"
                    }
                }
            },{
                test:/\.(eot|ttf|svg)$/,
                use: {
                    loader: 'file-loader',
                    ...
                }
            }
        ]
    }
}
复制代码
  • url-loader 其包含了file-loader的图片打包的功能,区别:就是不加任何配置项的时候,默认把图片打包成base64字符放在打包的js文件中,优点,加载js文件完成以后图片也加载好了,减小一次http请求,很差的地方就是当图片文件过大的时候,那么被放入图片的打包js文件也会很大,那么在加载技js文件的时候,加载耗时较长,也面回停留空白页的时间过长,所以增长配置项limit,
rules: [
  {
      test:/\.(jpg|jepg|png)$/,
      use: {
          loader: 'url-loader',
          options: {
              filename: '[name]_[hash].[ext]',
              outputPath: './image',
              limit: 20480, //==20480个字节==20kb
              //大于20kb就会打包成图片放在dist目录下面,小于则打包成base64字符串放在打包的js文件里面
          }
      }
  }
]
复制代码
  • 代码演示–2 –使用url先后加了limit配置以后的对比
//使用file-loader ,url-loader 须要安装
npm install file-loader --save-dev
npm install url-loader --save-dev
复制代码

img
img
img
img

style-loader css-loader sass-loader postcss-loader

  • 一样的对css,scss打包的时候,webpack都是不知道怎么去打包,因此须要借助相关的loader来执行打包,要同时安装css-loader,style-loader,css-loader只负责处理css文件,在获得css-loader处理而且合并以后的css内容文件时,须要使用style-loader挂在到页面header部分,这样样式的打包才会在页面生效,一样的若是sass文件时,还须要安装sass-loader,node-sass ,由于sass-loader是依赖于node-sass来执行解析sass文件的,因此执行顺序是,先是sass-loader将scss文件解析成css文件,其次css-loader处理这些被解析成的css文件,而后再有style-loader将这些内容挂在到页面的header部分,postcss-loader就是增长厂商前缀的,是最早执行的。
//安装loader
npm install style-loader css-loader sass-loader node-sass postcss-loader --save-dev
//在使用postcss-loader的时候须要借助插件
//autoprefixer
npm install autoprefixer -D
//使用postcss-loader还须要增长配置文件
//postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}
//webpack.config.js
module: {
    rules: [
        {
            test: /\.css$/,
            use: [
                "style-loader",
                <!--"css-loader",-->
                {
                    loader: "css-loader",
                    options: {
                        //表示css文件中又引入css文件,这样配置项可使每一层均可以走到(下-上,右-左)
                        importLoader: 2,
                        //配置支持css模块化,避免样式渲染全局,name.类名的方式调用
                        <!--modules: true-->
                    }
                }
                "postcss-loader"
            ]
        },{
            test: /\.scss$/,
            use:[
                  "style-loader",
                <!--"css-loader",-->
                {
                    loader: "css-loader",
                    options: {
                        importLoader: 2,
                        <!--modules: true-->
                    }
                },
                "sass-loader",
                "postcss-loader"
            ]
        }
    ]
}
复制代码
  • 代码演示–3

img

img

img

img

img

img

img

img

plugins

  • html-webpack-plugin: 做用就是帮咱们自动生成一个html,而且把打包好生成的js文件引入到html中,同时能够在src目录下建立一个html模板,而后能够设置配置项,根据这个html模板自动生成html放在dist目录下,,在打包完成以后开始执行
  • clean-webpack-plugin:做用就是把以前打包的dist目录删除掉,这个是在打包以前开始执行的
//首先安装html-webpack-plugin hlean-webpack-plugin
npm install html-webpack-plugin clean-webpack-plugin -D

//在webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new CleanWebpackPlugin('./dist')
    ]
}
复制代码
  • 代码演示 – 4 TypeError: CleanWebpackPlugin is not a constructor

img

img
img

//因此引用这个插件必需要使用对象结构
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
//这个插件使用默认配置就行了,若是要传入参数的话,必须以对象的形式
new CleanWebpackPlugin()/ new CleanWebpackPlugin({})
复制代码

img

sourceMap的配置

  • 这个是什么呢?,这个配置就是帮咱们作一个打包以后和源代码之间的一个映射关系,当打包的时候出现问题的时候,咱们并非要知道打包文件哪一行出现错误,而是要知道源代码的哪一行出现错误。
//webpack.config.js
module.exports = {
    //基本配置
    devtool: "source-map"
    //能够提示比较全面的错误信息,具体到哪一行哪一列第几个字符,而且映射文件会打包到打包文件里面
    devtool: "inline-source-map"
    //开发环境配置推荐
    devtool: "cheap-module-eval-source-map"
    //生产环境
    devtool: "cheap-module-source-map"
}
复制代码

webpackDevServer

  • 能够帮咱们监听文件的改动,还能够模拟服务器的一些特性,一旦src目录下的内容发生改变就会自动帮咱们打包文件而且自动刷新页面,
//先安装webpack-dev-server
npm install webpack-dev-server -D

//package.json
"scripts": {
    "watch": "webpack --watch",
    "start": "webpack-dev-server",
}
    
//webpack.config.js
devServer: {
    contentBase: './dist',//本地服务器加载的目录
    open: true,//打包完成以后自动帮咱们启动一个本地服务器,端口默认是8080,
    port: "",//端口能够自定义
    ...
}
复制代码

Hot Module Replace–HMR:热更新模块

  • 使用webpack-dev-server启动项目,帮咱们启动一个本地服务器,而且还会自动帮咱们打包,打包文件是放在内存当中,这样打包的速度更快,性能更好。
  • webpack自带的一个热更新模块插件 –HotModuleReplacementPlugin,可是做用于css和js的过程当中,相交于css热更新,js须要多一下代码,缘由是css-loader已经帮咱们写好了,像vue框架热更新也是同样,已经内置已经写好的代码,react框架也是借助babel的preset的配置来处理的
// weebpack.config.js
const webpack = require('webpack');

module.exports = {
    devServer: {
        contentBase: './dist',
        port: 8080,
        open: true,
        hot: true,//--开启热更新功能
        hotOnly: true,//阻止页面自动刷新,即便hot更新功能不起做用,浏览器也不自动刷新页面
    }
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]
}
//js
if(module.hot) {
    module.hot.accept('./number',() => {
        document.body.removeChild(document.getElementById('id'))
        number()//从新执行一下这个模块的函数
    })
}
复制代码
  • 代码演示–5
  • sourceMap
    img
    img
    img
    img
    img

babel处理es6语法

  • 对于普通浏览器目前是不支持es6语法的,可是支持es5语法代码,所以须要借助babel插件来作转换,这里能够查Babel的官方文档—这里省略一万步—这里面有使用场景的选择–选择webpack使用场景
//安装插件 --@babel/core是babel核心库
npm install babel-loader @babel/core -D
//同时要按装,babel-loader只是打通webpack的一个桥梁,并不会转义代码,须要借助@babel/preset-env 来作语法的转换
npm install @babel/preset-env -D
//还有继续安装@babel/polyfill -- 做用是帮助低版本的浏览器弥补缺失的变量以及函数,同时能够在options配置,根据业务代码来作低版本的缺失弥补,这样打包代码能够作到精简,注意的是,这个插件只适合作业务代码带包,由于会污染全局
npm install @babel/polyfill -D
//新建.babelrc文件,options配置能够放在这个文件里面
{
    presets: [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "chrome": "67"
                },
                "useBuiltIns": "usage"// 按需加载
            }
        ]
    ]
}
//webpack.config.js
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
<!--options: {-->
<!-- presets: [['@babel/preset-env',{targets: {chrome: "67",},useBuiltIns: 'usage'}]]--> <!--}--> //test code --es6 import '@babel/polyfill' const arr = [ new Promise(() => {}), new Promise(() => {}) ] arr.map(item => { console.log(item) }) 复制代码

webpack实现对react框架代码的打包

  • 须要借助@babel/preset-react插件,在转换react框架代码以后仍是要插件@babel/preset-env转换es6语法。
//使用安装插件
npm install react react-dom --save-dev
npm install @babel/preset-react --save-dev
//.babelrc中去引用插件
presets:[
    "@babel/preset-react"
]
//js--test-code
import React ,{ Component } from 'react'
import ReactDom from 'react-dom'
class App extends Compnent {
    render() {
        return(<div>herllo world</div>)
    }
}
ReactDom.render(<App/>,document.getElementById('root'));
复制代码

Tree shaking

  • 做用:这是webpack自带的一个功能,当引入一个模块的时候,不须要引入所有的代码,只须要引入被须要的代码,–就是摇树的意思,把没必要要的叶子所有摇掉。
  • 可是webpack中的tree shaking仅支持esmodule这种引入方式。
//webpack.config.js
module.exports = {
    plugins: [],
    optimization: {
        usedExports:true//只是在开发环境须要配置,在生产环境把不须要配置
    }

}
//package.json中 开发环境是会保留这段代码的
"sideEffects": ['*.css']---忽略相关模块不作tree shaking
复制代码

development和production模式的区分打包,webpack.dev.js,webpack.pord.js,webpack.common.js –能够把文件放到build文件中

//须要下载 webpack-merge
npm install webpack-merge -D
//dev
const webpack = require('webpack');
const devConfig = {
    mode: 'development',
    devtool: 'cheap-module-source-map',
    devServer: {
        contentBase: '../dist',//本地服务器加载的目录
        open: true, //打包完成以后自动打开浏览器
        // port: 8080,
        hot: true,//开启模块热更新更能
        hotOnly: true,//阻止页面刷新,即便热更新功能失效,也不会刷新页面
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ], 
    optimization: {
        usedExports:true,
    },
}
module.exports = devConfig;
//pord
const pordConfig = {
mode: 'production',//production 
}
module.exports = pordConfig;
//common
const path = require('path');
const merge = require('webpack-merge')
const devConfig = require('./webpack.dev.js');
const prodConfig = require('./webpack.prod.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const commonConfig = {
    entry: {
        main: './src/index.js'
    },
    module: {
        //规则数组类型--有不少不一样类型的打包规则
        rules: [
            // {
            // test: /\.(jpg|png|jpeg)$/,
            // use: {
            // loader: 'file-loader',
            // options: {
            // //placehold--占位符 name--文件名,hash--hash值,ext-文件后缀名
            // name: '[name]_[hash].[ext]',
            // //回把图片打包到dist目录下image文件夹里
            // outputPath: "./image"
            // }
            // }
            // },
            {
                test: /\.js$/,
                exclude:/node_modules/,
                loader: 'babel-loader'
            },
            {
                test: /\.(jpg|png|jpeg)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                    //placehold--占位符 name--文件名,hash--hash值,ext-文件后缀名
                        name: '[name]_[hash].[ext]',
                        //回把图片打包到dist目录下image文件夹里
                        outputPath: "./image",
                        limit: 204800,
                    },
                }
            },{
                test:/\.(eot|ttf|svg)$/,
                use: {
                    loader: 'file-loader',
                }
            },{
                test: /\.css$/,
                use: [
                    "style-loader",
                    "css-loader",
                    "postcss-loader"
                ]
            },{
                test: /\.scss$/,
                use: [
                    "style-loader",
                    "css-loader",
                    "sass-loader",
                    "postcss-loader"
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        // * All files inside webpack's output.path directory will be removed once, but the
        // * directory itself will not be. If using webpack 4+'s default configuration,
        // * everything under <PROJECT_DIR>/dist/ will be removed.
        new CleanWebpackPlugin({ verbose: true,cleanOnceBeforeBuildPatterns:['**/*']}),
    ],
    output: {
        filename: 'bundle.js',//打包成功后的文件名
        path: path.resolve(__dirname,'../dist'),//__dirname---表示跟web.config.js的同级根目录,打包以后的文件夹
    }
}

module.exports = (env) =>  {
    if(env&&env.production) {
        return merge(commonConfig,prodConfig)
    }else{
        return merge(commonConfig, devConfig)
    }
}
//package.js
"script": {
    "start": "webpack-dev-server --config ./build/webpack.common.js",
    "build": "webpack --env.production --config ./build/webpack.common.js",
    "dev": "webpack --env.development --config ./build/webpack.common.js"
}
复制代码
  • 代码演示 -6
    img
    img
    img

webpack和code Splitting:

  • 代码分割是webpack至关重要的一个特性,可让代码分割到不一样的文件中,一边按需加载或者并行加载这些文件,这样能够优化加载性能,以及用户体验会更好。
  • 代码分割其实只是在webpack中去实现代码分割,两种方式,同步代码分割只需optimization中配置便可,异步代码分割,webpack代码分割默认配置就是对异步代码进行代码分割,可是须要babel插件来作翻译,浏览器对异步的这种语法规则不支持。
//异步代码分割,安装babel插件,babel-plugin-dynamic-import-webpack
npm install babel-plugin-dynamic-import-webpack -D
//同步代码分割的话须要在optimization中配置splitChunks
//---在.babelrc中去配置一个plugins,
presets: [], 
plugins: ["dynamic-import-webpack"]
//webpack.common.js
optimization: {
    splitChunks: {
        chunks: 'all'//对同步代码和异步代码同时作代码分割
        chunks:'aysnc'//对异步代码作分割
    }
}
//test-code--index.js
function getComponent() { 
    return import('lodash').then(({default:_}) => {
        var element = document.createElement('div');
        element.innerHTML = _.join(['dell','lee'],'_');
        return element
    })
}
getComponent().then(element => {
    document.body.appendChild(element);
})
复制代码
  • splitChunksPlugin的底层配置中,异步代码会自动打包成一个文件0.js,这里须要指定引入异步代码文件的名字可使用魔法注释,这里就须要这个插件@babel/plugin-syntax-dynamic-import来作异步代码的转化,不能使用上面那个插件babel-plugin-dynamic-import-webpack,/webpackChuunkName:‘lodash’/,
  • chunks:aysnc这种异步代码能够解决打包文件过大,加载时间过长,分出第三方库和插件,须要的时候在进行按需加载和并行加载,提供加载性能。
npm install @babel/plugin-syntax-dynamic-import --save-dev
splitChunks: {
    chunks: async //--若是是async的话,只是对异步代码作代码分割,all是对异步和同步分都作代码分割
    minSize: 30000===30kb //大于30kb就会作代码分割,小于的话就作代码分割
    maxSize:0//可配可不配 --若是是50000===50kb, 会作二次分割 lodash 打包成1mb ,会拆成20个50kb代码分割
    minChunks: 1,//当这个模块使用几回的话在作代码分割,小于的设置的次数就不作代码分割
    maxAsyncRequests: 5,//同时加载的模块是5个,在打包前五个会帮你打包作代码分割,超过五个的话就不作代码分割
    maxInitialRequests: 3,//指整个网站首页进行加载的时候或者是入口文件进行加载的时候,入口文件会引入其余库,也只能最多三个,超过三个就不会作代码分割了
    automaticNameDelimiter: '~',//文件生成的时候,文件的中间会有一些链接符,
    name: true, ---//起什么名字,让cacheGroups中的名字有效
    cacheGroups: {//若是是同步的话会走完chunks以后会走这个配置,缓存组
        vendors: {
            test: /[\\/]node_modules[\\/]/,//--是同步代码发现是从node_modules引入的话,那么符合这个组会被打包成单独文件
            priority: -10
            filename: 'vendors.js'//是打包文件的名字
        }
        default: {
            priority: -20,//假设同时符合两个组,经过这个配置来设置优先级,值越大,优先级越高
            reuseExistingChunk: true,若是一个模块a,b,若是a使用了b,符合代码分割的要求,而后又符合default这个组,就不打包以前打包过的内容
            filename: 'common.js'
        }
    }
}
复制代码
  • lazy loading—就是支持esmodule这种语法,按需加载。
  • css代码分割: filename与chunkFilename区别:官网的代码分割插件:作的事情就是把css文件单独打包,不直接打包到js文件里面,这个插件不支持HMR,因此css代码分割插件通常应用到生产环境.
//安装插件
npm install mini-css-extract-plugin --save-dev
//线上环境单独生成的css文件须要作代码压缩合并
npm install optimize-css-assets-webpack-plugin -D
//optimization
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require(' optimize-css-assets-webpack-plugin')
//配置作更改
//开发环境使用规则默认
//线上环境
module: {
    rules: [
            use: ['MiniCssExtractPlugin.loader'] //全部使用style-loader所有替换,不使用style-loader 
        ]
},
optimization: {minimizer: [new OptimizeCssAssetsWebpackPlugin({})]},
plugins: [new MiniCssExtractPlugin({
    filename: '[name].css',//被文件直接引用走这个配置
    chunkFilename: '[name].chunk.css'//被间接引用的话是走这个配置项
})]
output: {
    filename: '[name].js',
    chunkFilename: '[name].chunk.js'//就是被js间接引用的打包文件就会走这个配置内容,
    path: path.resolve(__dirname,'../dist')
}
复制代码

但愿本文对你们有帮助。

想了解skFeTeam更多的分享文章,能够点这里,谢谢~

相关文章
相关标签/搜索