webpack

步骤:

  1. 1. npm install webpack webpack-cli --save-dev //安装webpack 开发环境
  2. 2. npm init -y //初始化packjon.json 不要用这一行,不然会报错

webpack默认支持 模块写法 commonjs 规范 node es6规范 esmodule
webpack-cli 解析用户传递的参数
npx是npm5.2之后出来的,可以运行node_modules里的.bin文件
所以npx webpack直接运行打包
打包后生成dist文件
npx webpack可以带参数,打包的是生产环境还是线上环境
npx webpack —mode development
开发环境是不会被压缩的
两个模式: 开发模式 生产模式
—model传入 这种比较麻烦,一般在package.json中配置命令
npm run scripts 里面可以配置对应的命令

"script":{
  "dev":"webpack --mode development"
  "build":"webpack --mode production"
}
npm run 运行这个命令的时候,会把node_modules这个.bin目录放到全局里面,有这个命令的时候回去执行这个webpack,执行完就被销毁了

image.png
但是这种写法是比较傻的,因为src 必须是index.js,dist里是main.js,下面我们自己建配置文件
webpack配置文件默认叫 webpack.config.js webpack.file.js
webpack 是基于nodejs 语法commonjs规范,默认导出的是配置对象
webpack.config.js

// webpack 是基于nodejs 语法commonjs规范
// 默认导出的是配置对象
const path = require('path')
module.exports = {
    mode:'development', // "dev":"webpack --mode development",这种写法比较繁琐。可以在这里配置mode,只保留"dev":"webpack",当前是开发模式
    // 入口 出口
    entry:path.resolve(__dirname,'./src/index.js'),  //写路径都采用绝对路径  不写相对路径防止路径变化发生错误, path.resolve解析路径
    output:{ //出口的配置
        filename:'bundle.js',  //打包后的文件 bundle js,放在dist里
        path:path.resolve(__dirname,'dist')
    }
}

webpack.config.js 也可以导出一个函数

module.exports = (env)=>{  //env是环境变量
    console.log(env)
    // 函数要返回配置文件,没返回会采用默认配置
}

在package.json配置

 "scripts": {
    "dev": "webpack --env.development",
     "build":"webpack --env.production",
 }

运行 npm run dev/build 可以看到运行的环境是dev还是build
另:实际操作的时候发现 运行报错,“ —env.development”, Unknown argument”,最后发现是版本问题,改成了
“webpack”: “^4.40.2”,
“webpack-cli”: “^3.3.8”
就好了
一般情况下,我们会分成两个模式,一个是开发模式,一个是生产模式,
新建build文件=>{
webpack.base.js
webpack.dev.js
webpack.prod.js
}
webpack.base.js
webpack-merge 主要用来合并配置文件的 npm install webpack-merge —save-dev


const dev = require('./webpack.dev')
const prod = require('./webpack.prod')
const path = require('path')
const {merge} = require('webpack-merge')
module.exports = (env)=>{  //env是环境变量
    let isDev = env.development;
    const base={
        entry:path.resolve(__dirname,'../src/index.js'),
        output:{
            filename:'bundle.js',
            path:path.resolve(__dirname,'../dist')
        }
    }
    // 这样运行命令就会走不通的环境啦
    if(isDev){
      return merge(base,dev)
    }else{
      return merge(base,prod)
    }
}

webpack.dev.js

module.exports = { 
   mode:'development'
}

webpack.prod.js

module.exports = { 
    mode:'production'
 }

package.json
通过 —config 指定执行的文件是哪一个

  1. 默认引用base 传入模式
  2. 分别引入dev,prod,在特定地方引入base
    "scripts": {
     "dev": "webpack --env.development --config ./build/webpack.base.js",
     "build": "webpack --env.production --config ./build/webpack.base.js"
    },
    

    webpack-dev-server

    如果是开发环境,要使用webpack-dev-server
    npm install webpack-dev-server —save-dev
    webpack-dev-server 是在内存中打包的,不会产生实体文件
    "scripts": {
     "dev:build": "webpack --env.development --config ./build/webpack.base.js", //也可能开发环境也需要打包,就可以这样配置一下,可以配置多个需要的环境打包
     "dev": "webpack-dev-server --env.development --config ./build/webpack.base.js",
     "build": "webpack --env.production --config ./build/webpack.base.js"
    },
    
    不希望每次打包都产生一个新文件,在dist目录下新建html,而是在自动生成html文件,并且自动引入打包的js。 单独创建一个存放模板文件 public,在每次打包后引用打包后的资源

    npm i html-webpack-plugin —save-dev

    所以安装这个插件帮我们自动生成
    并且我们希望在打包的时候清空之前的文件 安装下面的插件:

    npm install clean-webpack-plugin —save-dev

    webpack.base.js配置 ```javascript

const dev = require(‘./webpack.dev’) const prod = require(‘./webpack.prod’) const path = require(‘path’) const {merge} = require(‘webpack-merge’) const HtmlWebpackPlugin = require(‘html-webpack-plugin’) const {CleanWebpackPlugin} = require(‘clean-webpack-plugin’) module.exports = (env)=>{ //env是环境变量 let isDev = env.development; const base={ entry:path.resolve(dirname,’../src/index.js’), output:{ filename:’bundle.js’, path:path.resolve(dirname,’../dist’) }, plugins:[ // 在每次打包之前都清空dist目录下文件 new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns:[‘/*’] //默认清空目录 ,不写也可以 可以指定目录 ‘/*’所有目录下的所有文件 } ), new HtmlWebpackPlugin({ template:path.resolve(__dirname,’../public/index.html’), //打包模板 filename:’index.html’, minify:!isDev && { removeAttributeQuotes:true, // 移除 collapseBooleanAttributes:true //移除空格,即压缩 } }) ] } // 这样运行命令就会走不通的环境啦 if(isDev){ return merge(base,dev) //循环后面的配置,定义到前面去 }else{ return merge(base,prod) } }

webpack.dev.js
```javascript
const path = require('path')
module.exports = { 
   mode:'development',
   devServer:{ //开发服务的配置
       port:3000,
       compress:true, //gzip 可以提升返回页面的速度
       contentBase:path.resolve(__dirname,'../dist')  //webpack启动服务会在dist目录下 
   }
}

处理css

因为 只能识别loader,所以要把css转化成js以供识别 解析 css 需要两个loader css-loader style-loader

css-loader会解析css语法 style-loader 会将解析css 变成style标签插入到页面中 loader执行顺序,默认从下往上、从右往左 执行 ** 预处理器 文件后缀:.scss node-sass sass-loader .less less less-loader .stylus stylus stylus-loader

以scss为例
下载 插件
npm install node-sass sass-loader —save-dev
给css样式添加前缀 兼容其他浏览器: npm install postcss-loader —save-dev
postcss也需要一个插件: autoprefix
npm install autoprefix —save-dev
postcss-loader也需要一个配置文件

解析css的时候,就不能渲染dom 为了css 可以并行和js 一同渲染: mini-css-extract-plugin --save-dev 抽离css插件
webpack.config.js配置


const dev = require('./webpack.dev')
const prod = require('./webpack.prod')
const path = require('path')
const {merge} = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 开发的时候最好不用这个组件,因为慢,所以下面判断一下
module.exports = (env)=>{  //env是环境变量
    let isDev = env.development;
    const base={
        entry:path.resolve(__dirname,'../src/index.js'),
        module:{
            // 转化成什么文件,用什么去转,使用哪些loader
            // loader的写法[]  / {}  ''  数组 对象 字符串
            // 打包 css还需要处理一下 样式前缀

            // 解析css的时候,就不能渲染dom
            // css 可以并行和js 一同渲染 mini-css-extract-plugin
            rules:[
                // 但是这样有一个问题,如果css里m面引入了sass文件,就不会被解析了
                // {
                //     test:/\.css$/,
                //     use:['style-loader','css-loader']
                // },
                {
                    test:/\.css$/,
                    use:[ //是不是开发,如果是就用style-loader
                        isDev?'style-loader':MiniCssExtractPlugin.loader,{
                        loader:'css-loader',
                        options:{ //给loader传递参数
                            // 如果css文件引入其他文件@import   importLoaders:1表示这个之后的第一个,这里就是sass-loader开始解析的意思
                            importLoaders:2
                        }
                    },'postcss-loader','sass-loader']
                },
                {
                    test:/\.scss$/,
                    use:['style-loader','css-loader','sass-loader']
                }
            ]
        },
        output:{
            filename:'bundle.js',
            path:path.resolve(__dirname,'../dist')
        },
        plugins:[
            // 放置抽离出来的css文件,这个判断如果不满足条件,就返回了fasle,所以最后过滤掉一下,但是生成的css是没有经过压缩的,压缩还需要下载
            // npm install optimize-css-assets-webpack-plugin
           !isDev && new MiniCssExtractPlugin({
                filename:'css/main.css'
            }),
            // 在每次打包之前都清空dist目录下文件
            new CleanWebpackPlugin(
                {
                cleanOnceBeforeBuildPatterns:['**/*']  //默认清空目录 ,不写也可以  可以指定目录  '**/*'所有目录下的所有文件
                }
            ),
            new HtmlWebpackPlugin({
                template:path.resolve(__dirname,'../public/index.html'),  //打包模板
                filename:'index.html',
                minify:!isDev && {
                    removeAttributeQuotes:true,  // 移除
                    collapseBooleanAttributes:true  //移除空格,即压缩
                }
            })
        ].filter(Boolean)
    }
    // 这样运行命令就会走不通的环境啦
    if(isDev){
      return merge(base,dev) //循环后面的配置,定义到前面去
    }else{
      return merge(base,prod)
    }
}

这时候发现css不压缩,在webpack.prod.js配置一下

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
module.exports = { 
    mode:'production',
    optimization:{//优化项
        minimizer:[ //可以放压缩方案
           new OptimizeCSSAssetsPlugin(),//用了这个 js也得手动压缩  所以害得下载一个插件 npm install terser-webpack-plugin --save-dev
           new TerserWebpackPlugin()
        ]

    }
 }

配置好了之后js不压缩了,所以下载插件 npm install terser-webpack-plugin —save-dev,如上 配置一下,
另外,这个插件默认下载也会报错,查了下原因还是因为版本问题。
您正在使用Webpack 4和Terser ^5.0.0。此版本的Terser适用于Webpack 5,您需要"terser-webpack-plugin": "^4.2.3",package.json文件中设置版本

处理图片 +icon

npm install file-loader —save-dev
图片转成js ,用这个着插件,把当前图片拷贝到dist下,并且把拷贝的后的结果返回,然后引用
转化base64 插件
npm install url-loader —save-dev
配置:

  { //图表的转化
                    test:/\.scss$/,
                    use:['style-loader','css-loader','sass-loader']
                },
                {
                   test:/\.(woff|ttf|eot|svg)/,
                   use:'file-loader'
                },
                { //图片的转换
                    test:/\.(jpe?g|png|gif)$/,
                    use:{
                       loader: 'file-loader',
                    //    如果大于100kb的图片,会使用file-loader,解析的图片放在指定目录下
                       options:{
                           name:"image/[contentHash].[ext]", //contentHash就是当前内容的哈希,ext就是后缀
                           limit:100*1024
                       }

                     } //file-loader 默认的功能是拷贝作用
                //   我希望当前比较小的图片可以转化成base64,但是base64的缺点是可能转化后的图片会变得更大一些,好处就是不用发送http请求
                }

base64的缺点是可能转化后的图片会变得更大一些,好处就是不用发送http请求
另外修改一个地方,我们只需要在生产打包的时候清空dist就好了
webpack.prod.js

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = { 
    mode:'production',
    optimization:{//优化项
        minimizer:[ //可以放压缩方案
           new OptimizeCSSAssetsPlugin(),//用了这个 js也得手动压缩  所以害得下载一个插件 npm install terser-webpack-plugin --save-dev
           new TerserWebpackPlugin()
        ]

    },
     // 在每次打包之前都清空dist目录下文件
     plugins:[
        new CleanWebpackPlugin(
            {
            cleanOnceBeforeBuildPatterns:['**/*']  //默认清空目录 ,不写也可以  可以指定目录  '**/*'所有目录下的所有文件
            }
        ),
     ]
 }

处理js

es6-es5 有些api 不是es6语法,可能会用到装饰器 类的属性
babel 转化功能 vue-cli基于的是babel6来实现的
但是babel7了,
核心模块 @babel/core @babel/presets-env @babel-loader
默认会用@babel/core 会转化代码,转化的时候需要用@babel/presets-env 转化成es5 @babel相当于作用域
npm install @babel/core @babel/preset-env babel-loader —save-dev
class A{
a=1
}
这种语法还是不能识别的
插件 npm install @babel/plugin-proposal-class-properties —save-dev
识别装饰器
npm install @babel/plugin-proposal-decorators —save-dev
npm install —save core-js@2 —save-dev
转换后的代码上面增加了好几个函数声明,这就是注入的函数,我们称之为辅助函数。@babel/preset-env在做语法转换的时候,注入了这些函数声明,以便语法转换后使用
如果每个文件里都使用了class类语法,那会导致每个转换后的文件上部都会注入这些相同的函数声明。这会导致我们用构建工具打包出来的包非常大
们把这些函数声明都放在一个npm包里,需要使用的时候直接从这个包里引入到我们的文件里
所以就是以下插件
npm install —save-dev @babel/plugin-transform-runtime
npm install —save @babel/runtime

{  //解析js文件,默认会调用@babel/core  core会默认调用配置文件 .baberlc 注意此文件 presets是从下往上执行,plugin是从上往下  // loose 宽松的
                    // true是this.a = a,false是define property
                   test:/\.js$/,
                   use:'babel-loader'
                },

.babelrc

{
    "presets":[
        ["@babel/preset-env",{
            //使用的api 会自动转化,并且是按需加载
            "useBuiltIns":"usage",
            // 就是之前的babel-polufill,现在已经废弃了
            "corejs":2
        }],
        "@babel/preset-react"
    ],
    "plugins":[
        //解析装饰器
       ["@babel/plugin-proposal-decorators",{"legacy":true}],
       //解析类的属性
       ["@babel/plugin-proposal-class-properties",{"loose":true}],
       "@babel/plugin-transform-runtime"
    ]
}

还有react vue各种插件,太累了,不写了