webpack小笔记

371 阅读4分钟

一、webpack是什么?

	webpack是一种前端资源构建工具,静态模块打包器。前端所有的资源文件都会被当做模块,根据资源依赖关系,最后打包出一个或
    多个bundle(静态资源)

二、webpack五个核心概念

   1、entry

        打包文件入口,分析构建依赖图

   2、output

        打包文件出口(指定文件夹输出到哪里,怎样命名文件名)

   3、loader

		处理一些非JavaScript文件,如图片
        
   4、plugins

        可执行范围更广的任务, 比如打包优化、压缩、定义环境变量

   5、mode
   
   		开发环境或者生产环境(development or prodution)
        
        
   代码:
   const {resolve} = require('path')

	module.exports = {
        // 入口起点
        entry: './src/index.js',
        // 输出
        output: {
            filename: 'build.js', // 输出路径
            path: resolve(__dirname, 'build') // dirname 为nodejs变量名,代表当前文件目录的绝对路径
        },
        module: {
            rules:[
                {
                    test: /\.css$/, //匹配哪些文件
                    // 使用哪些loader,执行顺数重下到上
                    use: [
                        'style-loader', //创建style标签, 将js中的样式插入head中生效
                        'css-loader' //将css文件变成commonjs模块加载js中,内容是样式字符串
                    ]
                },
                {
                    test: /\.less$/, //匹配哪些文件
                    // 使用哪些loader,执行顺数重下到上
                    use: [
                        'style-loader', //创建style标签, 将js中的样式插入head中生效
                        'css-loader', //将css文件变成commonjs模块加载js中,内容是样式字符串
                        'less-loader' // 将less文件编译为css文件
                    ] 
                }
            ]
        },
        plugins: [],
        mode: 'development'
        // mode: 'production'
    }

三、打包css、less等样式文件

    {
        test: /\.css$/, //匹配哪些文件
        // 使用哪些loader,执行顺序重下到上
        use: [
        'style-loader', //创建style标签, 将js中的样式插入head中生效
        'css-loader' //将css文件变成commonjs模块加载js中,内容是样式字符串
        ]
    },
    {
        test: /\.less$/, //匹配哪些文件
        // 使用哪些loader,执行顺数重下到上
        use: [
        'style-loader', //创建style标签, 将js中的样式插入head中生效
        'css-loader', //将css文件变成commonjs模块加载js中,内容是样式字符串
        'less-loader' // 将less文件编译为css文件
        ] 
    }

    如果是其他样式文件需要下载不同的loader

四、打包html

    需要安装插件html-webpack-plugin
    引入const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    plugins:[
      new HtmlWebpackPlugin({
          template: './src/index.html'
      }),
	]
    

五、打包图片

    {
          test: /\.(jpg|png|gif)$/,
          // 下载url-loader, file-loader
          loader: 'url-loader',
          options: {
              // 图片小于8kb就会被base64处理, 优点:减少服务器压力;缺点:图片体积会变大。一般用于小图片
              limit: 30 * 1024,
              esModule: false,
              name: '[hash:10].[ext]'
          }
      },
      {
          test: /\.html$/,
          // 处理html里的img
          loader: 'html-loader'
      }
      

六、打包其他资源(字体图标等)

    {
        exclude: /\.(html|js|css|less|jpg|png|gif)$/,
        loder: 'file-loader',
        options: {
            name: '[hash:10].[ext]'
        }
    }

七、devServer

	// 只会在内存中编译,不会有任何输出
    // devServer启动指令: npx webpack-dev-server
    devServer: {
    	// 开启服务器,自动化启动默认浏览器,刷新浏览器等
        contentBase: resolve(__dirname, 'build'), // 构建之后的路径
        port: 3000, // 端口号
        open: true, // 自动打开默认浏览器
        compress: true // 开启gzip压缩
    }
    

八、提取js文件中的css为单独文件

    需要安装插件mini-css-extract-plugin
    引入const MiniCssExtractPlugin = require(mini-css-extract-plugin)
    
    {
        test: /\.css$/,
        use:[
            'MiniCssExtractPlugin.loader' // 取代style-loader
            'css-loader',
        ]
    },
    plugins:[
      new MiniCssExtractPlugin({
          filename: 'css/build.css' // 输出文件重命名
      })
    ]
	

九、css兼容性处理

	需要安装postcss-loader postcss-preset-env
    
    {
        test: /\.css$/,
        use:[
            'MiniCssExtractPlugin.loader' // 取代style-loader
            'css-loader',
        ],
        // 修改loader配置
        loader: {
        	ident: postcss,
            plugins: () => [
            	// postcss的插件,帮助postcss找到package.json文件里的browsersList的配
          置,通过配置加载指定的css兼容样式
            	requrie('postcss-preset-env')()
            ]
        }
    }
    
    "browsersList": {
    	"development": [
        	"last 1 chorme version",
        	"last 1 firefox version",
        	"last 1 safari version"
        ],
        "production": [
        	"> 0.2%",
            "no dead",
            "not op_mini all"
        ]
    }
    
    默认打包是生产环境,如果需要看开发环境,须设置process.env.NODE_ENV = 'development'
    

十、css压缩

	需要安装插件OptimizeCssAssetsWebpackPlugin
    引入const OptimizeCssAssetsWebpackPlugin = require(optimize-css-assets-webpack-plugin)
    
    plugins:[
       new OptimizeCssAssetsWebpackPlugin()
    ]
    

十一、js兼容

    1、基本js兼容,babel-loader @babel/core @babel/preset-env,不能处理高级语法如:promise

    2、全部兼容@babel-polyfill,但体积过大   // 安装后直接引入到入口文件
    
    3、按需处理 core.js
    
    {
        test: /\.js$/,
        exclude: /node_modules/
        loader: 'babel-loader'// 处理基本语法
        options: {
        	presets: ['@babel/preset-env'],
            // 按需处理js
            presets: [
            	[
                	'@babel/preset-env',
                    {
                    	useBuildIns: usage, // 表示按需加载
                        coreJs: {
                        	version: 3 // corejs版本
                        }
                        // 兼容到那个指定浏览器版本
                        targets: {
                        	chrme: '60',
                            ie: '9',
                            firefox: '60',
                            edge: '17',
                            safari: '10'
                        }
                    }
                ]
             ]
        }
    }
    

十二、压缩html,js

    生产环境下会自动压缩js,所以设置mode: 'production'
    
    压缩html需要安装插件html-webpack-plugin
    引入const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    plugins:[
      new HtmlWebpackPlugin({
          template: './src/index.html',
          miniy: {
              //移除空格
              collaspeWritespace: true//移除注释
              removeComments: true
          }
      }),
	]

十三、生产环境基本配置

    const {resolve} = require('path')

    const  MiniCssExtractPlugin  = require('mini-css-extract-plugin')
    const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 压缩css
    const HtmlWebpackPlugin = require('html-webpack-plugin')

    process.env.NODE_ENV = 'production' // 配置nodejs环境变量
    const commonCssLoader = [
      MiniCssExtractPlugin.loader,
      'css-loader',
      {
      loader: {
          ident: postcss,
          plugins: () => [
              // postcss的插件,帮助postcss找到package.json文件里的browsersList的配置,通过配置加载指定的css兼容样式
              requrie('postcss-preset-env')()
          ]
      }
      }
    ]
    module.exports = {
        entry: './src/index.js',
        output: {
            filename: 'build.js',
            path: resolve(__dirname, 'build')
        },
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use:[...commonCssLoader]
                },
                {
                    test: /\.less$/,
                    use:[
                        ...commonCssLoader,
                        'less-loader'
                    ]
                },
                // 在package.json中eslintConfig --> airbnb
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    // 优先执行
                    enforce: 'pre',
                    loader: 'eslint-loader',
                    options: {
                        fix: true
                    }
                },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: 'babel-loader',
                    options: {
                        // 按需处理js
                        presets: [
                            [
                                '@babel/preset-env',
                                {
                                    useBuildIns: usage, // 表示按需加载
                                    coreJs: {
                                        version: 3 // corejs版本
                                    },
                                    // 兼容到那个指定浏览器版本
                                    targets: {
                                        chrme: '60',
                                        ie: '9',
                                        firefox: '60',
                                        edge: '17',
                                        safari: '10'
                                    }
                                }
                            ]
                         ]
                    }
                },
                {
                    test: /\.(jpg|png|gif)$/,
                    loder: 'url-loader',
                    options: {
                        limit: 8 * 1024,
                        name: '[hash:10].[ext]',
                        esmodule: false,
                        outputPath: 'imgs'
                    }
                },
                {
                    test: /\.html$/,
                    loder: 'html-loader'
                },
                {
                    exclude: /\.(html|js|css|less|jpg|png|gif)$/,
                    loder: 'file-loader',
                    options: {
                        name: '[hash:10].[ext]',
                        outputPath: 'others'
                    }
                }
            ]
        },
        plugins:[
            new HtmlWebpackPlugin({
                template: './src/index.html',
                miniy: {
                    //移除空格
                    collaspeWritespace: true,
                    //移除注释
                    removeComments: true
                }
            }),
            new MiniCssExtractPlugin({
                filename: 'css/build.css'
            }),
            new OptimizeCssAssetsWebpackPlugin()
        ],
        mode: 'production'
    }
    

十四、开发环境优化打包速度

	HMR(hot module replacement)热模块替换,一个模块修改只打包替换对应修改的模块,极大的提升构建速度。
    
    css样式文件只需开启devServer hot配置项为true
    devServer: {
    	// 开启服务器,自动化启动默认浏览器,刷新浏览器等
        contentBase: resolve(__dirname, 'build'), // 构建之后的路径
        port: 3000, // 端口号
        open: true, // 自动打开默认浏览器
        compress: true, // 开启gzip压缩
        hot: true
    }
    
    html文件不需要做HMR功能,因为只有一个。只需在entry里加入
    entry: ['./src/index.js', './src/index.html']
    
    js文件(非入口文件)需要修改js代码
    if (module.hot) {
    	module.hot.accept(./xxx.js, function(){
        	执行回调函数
        })
    }

十五、 精确找到代码错误(source-map)

	只需配置devtool: 'source-map'
	开发环境:推荐使用evel-source-map 或者evel-cheap-moudle-source-map
    生产环境:推荐使用source-map 或者 cheap-moudle-source-map
    生产环境如需影藏源代码 hidden-source-map
    

十六、oneOf提升生产环境构建速度

	注意:不能两个配置处理统一类型文件
    module: {
        rules: [
             // 在package.json中eslintConfig --> airbnb
            {
                test: /\.js$/,
                exclude: /node_modules/,
                // 优先执行
                enforce: 'pre',
                loader: 'eslint-loader',
                options: {
                    fix: true
                }
            },
            // 以下loader只会匹配一个
            
            oneOf: [
            	{
                  test: /\.css$/,
                  use:[...commonCssLoader]
                },
                {
                    test: /\.less$/,
                    use:[
                        ...commonCssLoader,
                        'less-loader'
                    ]
                },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: 'babel-loader',
                    options: {
                        // 按需处理js
                        presets: [
                            [
                                '@babel/preset-env',
                                {
                                    useBuildIns: usage, // 表示按需加载
                                    coreJs: {
                                        version: 3 // corejs版本
                                    },
                                    // 兼容到那个指定浏览器版本
                                    targets: {
                                        chrme: '60',
                                        ie: '9',
                                        firefox: '60',
                                        edge: '17',
                                        safari: '10'
                                    }
                                }
                            ]
                         ]
                    }
                },
                {
                    test: /\.(jpg|png|gif)$/,
                    loder: 'url-loader',
                    options: {
                        limit: 8 * 1024,
                        name: '[hash:10].[ext]',
                        esmodule: false,
                        outputPath: 'imgs'
                    }
                },
                {
                    test: /\.html$/,
                    loder: 'html-loader'
                },
                {
                    exclude: /\.(html|js|css|less|jpg|png|gif)$/,
                    loder: 'file-loader',
                    options: {
                        name: '[hash:10].[ext]',
                        outputPath: 'others'
                    }
                }
            ]
        ]
    }
    

十七、优化生产环境缓存

	开启babel缓存
    {
        test: /\.js$/,
        exclude: /node_modules/,
        // 优先执行
        enforce: 'pre',
        loader: 'eslint-loader',
        options: {
            fix: true
        },
        // 第二次构建时,读取缓存
        cacheDirectory: true
    }
    
    开启文件资源缓存,需要在服务端代码改动,资源文件名也需要加hash值
    以nodejs为例:
    app.use(express.static('bulid', {maxAge: 1000 * 3600}))
    
    
    问题:js和css共用了同一个hash值,这样就会其他文件缓存失效
    解决:资源文件名添加contentHash值
    

十八、tree shaking去除无用代码(减少代码体积)

	使用前提:使用ES6模块化,为生产环境(有可能会删除css等其他文件,需要在package.json配置)

十九、代码分割打包

	1、多入口引入文件(该文件无需引入)
    entry: ['./src/index.js', './src/test.js']
    output: {
        filename: 'js[name].[conmtenthash].[10].js', // 输出的模块模就不一样
        path: resolve(__dirname, 'build')
    }
    
    2、如果引入了公共的js文件(多入口)
    // 将node_module里面的文件单独打包为一个bundle
    optimization: {
    	splitChunks: {
        	chunks: 'all'
        }
    }
    
    3.通过js代码单独打包某一个js文件,import动态导入语法
    
    import(/*webpackChunkName: 'test'*/./test.js).then(res => {
    }).catch(err =>{
    })
    
    

二十、PWA

二十一、多进程打包