# babel

# 1 执行编译的命令

在 package.json 文件中添加执行 babel 的命令

(在 scripts 中添加:"build":"babel src -d dist")

  • babel src --out-dir dist*

# 2.Babel 的配置文件

  • 安装配置文件 npm install @babel/preset-env@7.11.0--save-dev

  • 创建配置文件.babelrc, 并配置

{

"presets":["@babel/preset-env"]*

}

# 3 .npm run build 进行打包

# webpack

# webpack 是什么

const { webpack } = require("webpack")

webpack 是静态模块打包器,当 webpack 处理应用程序时,会将所有这些模块打包成一个或多个文件

处理 js css 图片 图标字体 静态文件

# 使用 webpack

1 初始化项目 npm init

2 安装 webpack 需要的包

npm install --save-dev webpack-cli@3.3.12 webpack@4.44.1

3 配置 webpack (创建 webpack.config.js)

创建配置信息 (官网查找)

4 package.json 的 script 中配置 webpack 命令

"webpack": "webpack --config webpack.config.js"

5 npm run webpack

# output 和 entry (webpack.config.js 中配置)

1 entry 指定入口文件

entry 中配置多个入口文件 :

entry: {

main: './src/index.js' ,

search: './src/search.js

}

2 output 中配置多个出口文件

单个出口:

output: {

path: path.resolve(__dirname, 'dist'), //出口文件夹路径

filename: 'bundle.js' //出口文件名称

}

// 注意如果配置了多个入口,但是只配置了一个出口,会报错

// 此时采用动态输出名指定输出文件:使用 [name] 指定动态输出文件

output: {

path: path.resolve(__dirname, 'dist'),

filename: '[name].js'

}

# loader ( 将 webpack 和其他工具进行联通 )

1 什么是 loader (加载器,webpack 本身是用来打包 js , 要想打包 css 图片等静态资源和模块,必须要使用 loader)

2 babel-loader (webpack 中使用 babel , 先用 babel 将 ES6 代码转成 ES5 的代码,然后再交给 webpack 进行打包)

(1) 安装:

npm install--save - dev babel - loader@8.1.0 @babel/core@7.11.0 @babel/preset - env@7.11.0

(2) 创建 babel 配置文件

.babelrc 文件,并且配置

{

"presets":["@babel/preset-env"]*

}

(3) 配置 loader 再 webpack.config.js 中,再原有的基础之上

module: {

配置多个loader规则

rules: {

//匹配需要处理的文件类型

test: /\.js$/,

//排除不需要打包的的文件类型(node modules

exclude:/node_modules/,

// 联通webpack和babel ,处理文件

loader: 'babel-loader'

}

}

(4) 但是这样也只是转义了语法,ES6 代码中的一些新的 API 无法转成 ES5,此时需要引入模块,然后使用 API

// 这也就是 babel/polyfill 的作用

# 使用 babel/polyfill ( core-js )

(1) 安装

npm install --save-dev core-js@3.6.5

(2) 在需要处理的 js 文件中引入 core-js 稳定版

import 'core-js/stable' (在要处理的js文件中引入)

(3)npm run webpack 进行打包处理

# plugins

1 plugins 介绍,插件,loader 被用于转成某些类型的模块,而插件则可以用于执行范围更广的任务

需要什么功能就使用对应功能的插件

2 举例应用:html-webpack-plugin 插件

html 中需要在 html 中手动添加 js 文件 , 此插件可以直接将 js 的引入嵌入 html 文件中

(1) 安装

npm install --save-dev html-webpack-plugin@4.3.0

(2) 配置 html-webpack-plugin 插件 (在 webpack.config.js 中引入)

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode: 'development',
  entry: {
    // 单入口
    // index: './src/index.js'
    
    // 多入口
    index: './src/index.js',
    search: './src/search.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  },
  plugins: [
    // 单入口
    // new HtmlWebpackPlugin({
    //   template: './index.html'
    // })
    
    // 多入口
    new HtmlWebpackPlugin({
      template: './index.html',
      filename: 'index.html',
      chunks: ['index'],
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      }
    }),
    new HtmlWebpackPlugin({
      template: './search.html',
      filename: 'search.html',
      chunks: ['search']
    })
  ]
};

# webpack 处理 css 文件 (可以在 js 中引入 css 文件 ,webpack 将 css 文件当成模块)

# 一 css-loader

//1 js 中 import '/src/index.css'

// 2 安装 css-loader

// npm install --save-dev css-loader@4.1.1

// 3 webpack.config.js 中配置 module

module: {
  rules: [
    {
      test: /\.css$/,
      loader: 'css-loader'
    }
  ]
}

// 此时 css-loader 帮助 webpack 认识了 css 文件,然后引入,但是不会生效 (因为没有 style 标签)

// 此时还需要一个 style-loader

# 二 style-loader

// (1) 安装

npm install --save-dev style-loader@1.2.1

// (2) 配置 style-loader(webpack.config.js 中)

module: {
  rules: [
    {
      test: /\.css$/,
      //  loader:'css-loader'
      use: ['style-loader', 'css-loader']  // 注意会从右向左的顺序执行
    }
  ]
}

// 三 如果不想直接使用 css 文件,而是想要用 link 标签引入外部 css 文件,需要用到一个插件

mini-css-extract-plugin

// (1) 安装

npm install --save-dev mini-css-extract-plugin@0.9.0

// (2)在 webpack.config.js 中导入

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

// (3)在 webpakc.config.js 中配置( rules 中 use 和 plugins)

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'js/[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        // loader: 'css-loader'
        use: ['MiniCssExtractPlugin.loader', 'css-loader']  // 注意会从右向左的顺序执行
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html',
      filename: 'index.html'
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].css'
    })
  ]
};

# 【9】使用 loader 处理图片问题

# 四 使用 file-loader 处理 CSS 文件中的图片

//webpack 只能处理内部的资源,外部的远程图片不用考虑 webpack

//webpack 不认识 png 等格式结尾的文件,此时就需要使用 file-loader

// (1) 安装 file-loader:

npm install --save-dev file-loader@6.0.0

// (2) 在 webpack.config.js 的 rules 中配置 file-loader

// webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'js/[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../'
            }
          },
          'css-loader'
        ]
      },
      {
        test: /\.(jpg|png|gif)$/,
        use: {
          loader: 'file-loader',
          options: {
            name: 'img/[name].[ext]' // 指定图片名称
          }
        }
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].css'
    })
  ]
};

// (注意 file-loader 处理的图片会放到新的目录,此时需要和 minicss 插件配合使用)

# 五 使用 html-withimg-loader 处理 HTML 图片 (处理 html 中使用的图片)

// (1)安装

npm install --save-dev html-withimg-loader@0.1.16

// (2)webpack.config.js 的 module 的 rules 中配置文件

{
   test: /\.(html|html)$/,  // 待处理文件
loader: 'html-withimg-loader'
}

// (3)npm run webpack 进行打包

// 但是注意他与 file-loader 的配合使用,过程中会将图片当成模块,解决方法在 module 中 rules 中配置

// webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'js/[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
    {
      test: /\.css$/,
      use: [
        {
          loader: MiniCssExtractPlugin.loader,
          options: {
            publicPath: '../'
          }
        },
        'css-loader'
      ]
    },
    {
      test: /\.(jpg|png|gif)$/,
      use: {
        loader: 'file-loader',
        options: {
          name: 'img/[name].[ext]',
          esModule: false // 不将 html 中引入的图片当成模块处理
        }
      }
    }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].css'
    })
  ]
};

# 六 使用 file-loader 处理 js 图片

将 js 中引入的图片的地址更换成打包后的图片的地址
在 webpack.config.js 的 module 中的 rules 中进行配置

// webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'js/[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
    {
      // 匹配图片文件
      test: /\.(jpg|png|gif)$/,
      use: {
        // 使用 file-loader 处理
        loader: 'file-loader',
        options: {
          name: 'img/[name].[ext]', // 指定输出文件的名称和路径
          esModule: false // 不将 html 中引入的图片当成模块处理
        }
      }
    }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].css'
    })
  ]
};

# 七 使用 url-loader 处理图片

( file-loader 的功能过于单一 ,url 功能更加全面,但其底层是由 file-loader 来封装的,配置时,只需要配置 url-loader 即可)

(1)安装 url-loader

npm install --save-dev url-loader@4.1.0

(2)配置 url-loader

webpack 中的 module 中的 rules 下进行配置

{
  test: /\.(jpg|png|gif)$/,
  use: {
    loader: 'url-loader',
    options: {
      name: 'img/[name].[ext]',   // 设置文件夹名称和文件名称
      esModule: false,   // 设置其引入不是一个路径
      limit: 3000   // 将 3kb 以内的图片转成 base64 格式,存到 js 中
    }
  }
}

使用 url-loader 的前提时要引入 file-loader(url-loader 是由 file-loader 封装而来)

# 八 使用 webpack-dev-server 搭建开发环境

比如:自动打包(打包热启动),当修改文件内容时,自动进行打包处理(打包之后的文件不会生成在磁盘中,而是存在内存里)

(1)安装:

npm install --save-dev webpack-dev-server@3.11.0

(2) 配置命令(在 package.json 的 scripts 中配置)

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",   // 测试命令
  "webpack": "webpack",   // 运行 webpack 命令
  "dev": "webpack-dev-server"   // 运行 webpack-dev-server 命令
  // "dev": "webpack-dev-server --open chrome"  // 重新打包,并且打包之后自动开启 Chrome 浏览器
}

# webpack 配置示例

const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin")
const CopyWebpackPlugin = require("copy-webpack-plugin")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const {VueLoaderPlugin} = require("vue-loader")
const path = require("path")
const {DefinePlugin} = require("webpack")
const TerserWebpackPlugin = require("terser-webpack-plugin")
const getStyleLoaders = (pre) => {
    return [
        // 针对 vue 项目
        isProdcution ? MiniCssExtractPlugin.loader : "vue-style-loader",
        'css-loader',
        {
            // 处理 css 兼容性
            // 配合 package.json 之中的 browserslist 来指定兼容性做到什么程度
            loader: 'postcss-loader',
            options: {
                postcssOptions: {
                    plugins: ['postcss-preset-env']
                }
            }
        },
        pre && pre === "sass-loader" ? {
            loader: "sass-loader",
            options: {
                additionalData: `@use "@/styles/element/index.scss" as *;`
            }
        } : pre === "less-loader" ? {
            loader: 'less-loader',
            options: {
                lessOptions: {
                    modifyVars: {
                        'primary-color': '#1DA57A',
                        'link-color': '#1DA57A',
                        'border-radius-base': '2px',
                    },
                    javascriptEnabled: true,
                }
            },
        } : pre
    ].filter(Boolean)
}
const isProdcution = process.env.NODE_ENV === "production" ? true : false
let cdn = isProdcution ? {
    // css: ["https://cdn.jsdelivr.net/npm/element-plus/dist/index.css"],
    css: [
        "https://cdn.jsdelivr.net/npm/ant-design-vue@3.2.20/dist/antd.min.css"
    ],
    js: [
        "https://cdnjs.cloudflare.com/ajax/libs/vue/3.3.4/vue.global.prod.min.js",
        'https://cdnjs.cloudflare.com/ajax/libs/vue-router/4.2.2/vue-router.global.prod.min.js',
        "https://cdn.jsdelivr.net/npm/ant-design-vue@3.2.20/dist/antd.min.js"
        // "https://cdn.jsdelivr.net/npm/element-plus"
    ]
} : {}
module.exports = {
    entry: './src/main.js',
    output: {
        filename: "static/js/[name].js",
        path: isProdcution ? path.resolve(__dirname, "../dist") : undefined,
        chunkFilename: "static/js/[name].[hash:10].chunk.js",
        assetModuleFilename: "static/assets/[hash:10][ext]",
        clean: true
    },
    devtool: "source-map",
    module: {
        rules: [
            {
                oneOf: [
                    {
                        test: /\.css$/,
                        use: getStyleLoaders()
                    },
                    {
                        test: /\.less$/,
                        use: getStyleLoaders("less-loader")
                    },
                    {
                        test: /\.s[ac]ss$/,
                        use: getStyleLoaders("sass-loader")
                    },
                    {
                        test: /\.styl$/,
                        use: getStyleLoaders("stylus-loader")
                    },
                    // 处理图片
                    {
                        test: /\.(jpe?g|png|gif|webp)$/,
                        type: 'asset',
                        parser: {
                            dataUrlCondition: {
                                maxSize: 10*1024 // 小于 10kb
                            }
                        }
                    },
                    // 处理其他字体资源
                    {
                        test: /\.(woff2?|ttf)$/,
                        type: 'asset/resource',
        
                    }
                ]
            },
            // 处理 js  eslint babel
            {
                test: /\.js$/,
                include: path.resolve(__dirname, "../src"),
                loader: "babel-loader",
                options: {
                    // 开启缓存
                    cacheDirectory: true,
                    // 缓存不需要压缩
                    cacheCompression: false
                }
            },
            {
                test: /\.svg$/,
                type: 'asset',
                loader: 'svgo-loader',
                exclude: [path.resolve(__dirname, '../src/icons')],
                options: {
                    multipass: true,
                    js2svg: {
                        indent: 2,
                        pretty: true,
                    }
                }
            },
            {
                test: /\.svg$/,
                include: [path.resolve(__dirname, '../src/icons')],
                use: [
                    {
                        loader: 'svg-sprite-loader',
                        options: {
                            symbolId: 'icon_[name]'
                        }
                    }
                ]
            },
            {
                test: /\.vue$/,
                loader: "vue-loader",
                options: {
                    cacheDirectory: path.resolve(__dirname, "../node_modules/.cache/vue-loader")
                }
            }
        ]
    },
    resolve: {
        extensions: [".vue", ".js", ".json"],
        alias: {
            '@': path.resolve(__dirname, '../src')
        }
    },
    plugins: [
        new EslintWebpackPlugin({
            context: path.resolve(__dirname, "../src"),
            exclude: "node_modules",
            cache: true,
            cacheLocation: path.resolve(__dirname, "../node_modules/.cache/.eslintcache")
        }),
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, "../public/index.html"),
            cdnTag: cdn
        }),
        new VueLoaderPlugin(),
        // 定义环境变量 cross-env 定义的环境变量是给打包工具使用的
        // DefinePlugin 是给源代码使用的,解决 vue3 的警告问题
        new DefinePlugin({
            __VUE_OPTIONS_API__: true,
            __VUE_PROD_DEVTOOLS__: false
        }),
        isProdcution && new MiniCssExtractPlugin({
            filename: "static/css/[name].[contenthash:10].css",
            chunkFilename: "static/css/[name].[contenthash:10].chunk.css"
        }),
        isProdcution && new CopyWebpackPlugin({
            patterns: [
                {
                    from: path.resolve(__dirname, "../public"),
                    to: path.resolve(__dirname, "../dist"),
                    globOptions: {
                        // 忽律 index.html 文件
                        ignore: ["**/index.html"]
                    }
                }
            ]
        })
    ].filter(Boolean),
    optimization: {
        splitChunks: {
            chunks: 'all',
            cacheGroups: {
                vue: {
                    test: /[\\/]node_modules[\\/]vue(.*)?[\\/]/,
                    name: "vue-chunk",
                    priority: 30
                },
                "ant-design-vue": {
                    test: /[\\/]node_modules[\\/]ant-design-vue(.*)?[\\/]/,
                    name: "ant-design-vue-chunk",
                    priority: 20
                },
                // elementPlus: {
                //     test: /[\\/]node_modules[\\/]element-plus(.*)?[\\/]/,
                //     name: "elementPlus-chunk",
                //     priority: 20
                // },
                libs: {
                    test: /[\\/]node_modules[\\/]/,
                    name: "libs-chunk",
                    priority: 10
                }
            }
        },
        // 代码分割会导致缓存失效,因为每次都需要重新引入,名字就会发生变化
        runtimeChunk: {
            name: entrypoint => `runtime-${entrypoint.name}.js`
        },
        minimize: isProdcution,
        minimizer: [
            new CssMinimizerWebpackPlugin(),
            new TerserWebpackPlugin()
        ]
    },
    mode: isProdcution ? "production" : "development",
    performance: false,
    devtool: isProdcution ? "source-map" : "cheap-module-source-map",
    devServer: {
        host: 'localhost',
        port: 3000,
        open: false,
        hot: true,
        // 解决 html5 history 刷新 404 的问题
        historyApiFallback: true
    }
}

# 实现 miniwebpack

# 前置知识

我们都知道 webpack 是基于 babel 进行语法转换的,因此我们需要提前了解一些 babel 的使用方法:

  • @babel/parser 模块:用于将 js 代码转为抽象语法树
  • @babel/traverse 模块:用于遍历和操作抽象语法树(处理导入的模块)
  • @babel/core 模块:babel 的核心模块,用于将抽象语法树转换为代码信息对象(包含重要的 code 属性,表示转换后生成的代码)
  • @babel/preset-env 模块:babel 中的一个预设,可以在 babel.transformFromAst 中第三个参数中 presets 字段传入,可以根据当前环境将代码转成相应的兼容版本。

# 流程图

miniwebpack

# 开始编码

const fs = require("fs");
const path = require("path");
// @babel/parser 用于将 js 代码转化为抽象语法树
const parser = require("@babel/parser");
// @babel/traverse 用于遍历和操作抽象语法树
const traverse = require("@babel/traverse").default;
// Babel 的核心功能包含在 @babel/core 模块中
const babel = require("@babel/core");
// 1. 分析依赖
function parseModules(file) {
  const entry = getModuleInfo(file);
  const temp = [entry];
  const depsGraph = {};
  getDeps(temp, entry);
  temp.forEach((moduleInfo) => { // 遍历全部模块信息数组
    depsGraph[moduleInfo.file] = { // 映射 file 路径和 code、deps
      deps: moduleInfo.deps,
      code: moduleInfo.code,
    };
  });
  return depsGraph;
}
function getDeps(temp, {deps}) {
  Object.keys(deps).forEach((key) => {
    const child = getModuleInfo(deps[key]);
    temp.push(child);
    getDeps(temp, child);
  });
}
function getModuleInfo(file) {
  // 读取文件
  const body = fs.readFileSync(file, "utf-8");
  // 转化为 AST
  const ast = parser.parse(body, {sourceType: "module"});
  const deps = {};
  traverse(ast, {
    // 获取 import 导入的模块
    ImportDeclaration({node}) {
      const dirname = path.dirname(file);
      // 获取标准化路径
      const absPath = "./" + path.join(dirname, node.source.value);
      deps[node.source.value] = absPath;
    },
  });
  const {code} = babel.transformFromAst(ast, null, {
    // 使用预设
    presets: ["@babel/preset-env"],
  });
  const moduleInfo = {file, deps, code};
  return moduleInfo;
}
// 2. 实现 bundle
function bundle(file) {
  // 将模块转为引用路径和映射 code、deps 的对象
  const depsGraph = JSON.stringify(parseModules(file));
  return `(function (graph) {
    function require(file) {
      function absRequire(realPath) {
        return require(graph[file].deps[realPath]);  //递归调用获取返回值
      }
      var exports = {};   //exports对象,用于存储模块的返回值信息
      (function (require, exports, code) {
        eval(code);   //eval函数用于执行字符串的js代码,传入require,exports和code
      })(absRequire, exports, graph[file].code);
      return exports;
    }
    require('${file}');
  })(${depsGraph});`;
}
const content = bundle("./src/index.js");
// 将内容写入到输出文件 
fs.writeFileSync("./dist/bundle.js", content);
//webpack 打包后的 js 文件就是一个立即执行函数,传入的参数是一个对象,对象的键是模块路径,值是模块函数代码
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

dmq 微信支付

微信支付

dmq 支付宝

支付宝