ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

模块化开发与规范化标准

2021-01-04 20:57:57  阅读:166  来源: 互联网

标签:模块化 require loader webpack 开发 babel 规范化 js css


概述

1.模块化演变过程
2.模块化规范
3.常用的模块化打包工具
4.基于模块化工具构建现代web应用
5.打包工具的优化技巧

模块化演变过程

1.污染全局作用域
2.命名冲突问题
3.无法管理模块依赖关系

模块化规范的出现

1.CommonJS
一个文件就是一个模块
每个模块都有单独的作用域
通过module.exports导出成员
通过require函数载入模块
是以同步模式加载模块(在浏览器中 加载缓慢)
2.AMD(Asynchronous Module Definition) Require.js

ES Modules 特性

1.CommonJS
一个文件就是一个模块
每个模块都有单独的作用域
通过module.exports导出成员
通过require函数载入模块
是以同步模式加载模块(在浏览器中 加载缓慢)
2.AMD(Asynchronous Module Definition) Require.js

ES Modules 特性

1.自动采用严格模式,忽略’use strict’
2.每个ESM模块都是单独的私有作用域
3.ESM是通过cors去请求外部JS模块的(外模模块需要支持跨域)
4.ESM的script标签会延迟执行脚本(异步)

ES Modules 导出和导入

  export { foo } 导出一个成员引用 不是一个对象
  import { foo } from './*.js' 导入

  export default foo 默认导出 可以导出一个对象
  import abc from './*.js'  导入变量名可以变化

babel 兼容性方案

yarn add @babel/node @babel/core @babel/preset-env --dev
babel模块依赖一些核心模块 基于插件形式实现的
@babel/preset-env 是一个插件的集合 一个插件实现一个功能转换
yarn babel-node index.js --presets=@babel/preset-env
@babel/preset-env可以放在.babelrc配置 {"presets":["@babel/preset-env"]}
yarn babel-node index.js

一.Webpack 的构建流程主要有哪些环节?如果可以请尽可能详尽的描述 Webpack 打包的整个过程。

环节

1.初始化项目 安装webpack
2.配置文件webpack.config.js
3.配置项目入口(entry)、输出路径(output)、开发模式(mode)等
4.根据要加载的文件类型,安装配置不同的loader加载器
5.实现非loader的功能,安装相应的plugins
6.配置devserver 开启自动化编译和浏览器预览
7.配置optimization 进行项目优化操作

打包过程

1.执行打包命令(webpack)
2.通过webpack.config.js配置文件的entry入口配置开始查找项目依赖资源
3.根据配置的loader解析不同的资源,输出打包后的资源
4.在webpack打包过程中根据不同的环境配置不同plugin做一些额外的工作和一些优化操作
5.最后(output)输出Chunk文件 可多个或静态不变

plugin:主要是在webpack构建的不同阶段执行一些额外的工作,比如拷贝静态资源、清空打包后的文件夹等

1.通过钩子机制实现
2.plugin必须是一个函数或包含apply方法的对象
3.在方法体内通过webpack提供的API获取资源做响应处理
4.将处理完的资源通过webpack提供的方法返回该资源

class MyPlugin{
  // 传入相应的配置信息
  constructor(options){
  }

  // 将Compiler对象传递进来
  // 然后通过这个对象来注册钩子函数
  apply(compiler){
      // 注册emit钩子方法
      // compilation是一个上下文,
      compiler.hooks.emit.tap("MyPlugin",compilation=>{
          //在这里执行我们的方法来修改内容
        })
    }
}

二.webpack配置vue开发的流程

1.首先我们需要安装webpack webpack-cli到我们的开发依赖中

一阶段:在module.common.js文件 配置项目入口(entry)、输出路径(output)

二阶段:

    1.根据要加载的文件类型,安装配置不同的loader加载器
      因为我们项目是vue 所以我们需要安装vue-loader的依赖来对vue文件进行解析和转换
    2.接下来,由于我们项目中使用的是less,所以我们需要安装less-loader来对less进行解析和编译,同时,我们还需要安装css-loader和style-loader来对css文件和vue中的style标签进行解析
    注意:如果use是多个 顺序是从后到前执行 css解析需要style、css loader一起使用
    3.接下来是对js文件的解析,这里我们需要使用到babel-loader,将ES6+转为ES5
    注意:babel-loader内部会调用@babel/core 进行语法转换,@babel/core的转换依赖预设@babel/preset-env
    4.再然后是对图片文件的处理,我们使用url-loader来处理。由于url-loader是基于file-loader的

三阶段:

    1.因为是vue项目,需要使用一个VueLoaderPlugin插件引入
    2.此时我们发现没有html的解析文件,如果所以我们需要安装一个htm-webpack-plugin,用于指定html模板来生成我们的index.html,还可以设置title、meta等
      由于过程BASE_URL会报错所以我们需要使用webpack的DefinePlugin来定义一下BASE_URL的位置

四阶段:分配不同环境 通过webpack-merge 合并其他配置 类似Object.assign()

   1.开发环境的配置
     (1)mode模式分为三种 分别是 production、development 和 none 开发选择development
     (2)指定sourceMap 开发中方便找到源码中错误的位置
     (3)开发环境需要配置eslint 在保存时检查代码规范
     (4)配置devServer 启动热更新 提高开发效率 或使用代理服务 解决跨域
   1.生产环境的配置  
     (1)mode选择production
     (2)去除sourceMap 防止源码暴露
     (3)我们所有的代码都打包到了一个js文件中,接下来,我们首先把css样式文件分离出来,这一步我们需要使用到mini-css-extract-plugin,并且我们需要更改一下less和css文件的loader
     (4)我们需要做的就是对css文件和js文件的压缩和分包,并且通过webpack来去掉代码中的dubugger,console等,这一步我们需要使用optimize-css-assets-webpack-plugin 和 terser-webpack-plugin

最后:由于命令行的长度太长了,所以我们可以吧命令直接使用npm script的方式来执行,具体就是修改package.json里面的东西

webpack.common.js 代码演示

const path = require("path")
const VueLoaderPlugin = require("vue-loader/lib/plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")

// 公共的打包配置
module.exports = {
    // 入口文件 可以多个入口
    // entry: {
    //     index: './src/index.js',
    //     album: './src/album.js'
    // },
    entry: "./src/main.js",
    // 输出文件
    output: {
        // __dirname生成绝对路径
        path: path.resolve(__dirname, "dist")
    },
    module: {
        rules: [
            {
                // 解析vue文件
                test: /\.vue$/,
                use: ["vue-loader"]
            },
            {
                // 对js进行代码转译
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        // babel-loader内部会调用@babel/core 进行语法转换,@babel/core的转换依赖预设@babel/preset-env和插件plugin 
                        presets: ['@babel/preset-env']
                    }
                }
            },
            {
                // 对图片文件的处理 由于url-loader 是基于file-loader的,所以我们需要同时安装这个依赖
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                use: {
                    loader: "url-loader",
                    // 限制图片大小 超过10k文件存储,不超过转base64
                    options: {
                        limit: 10 * 1024,
                        // 不加 src中会是一个object module
                        esModule: false
                    }
                }
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
        // 用于生成 index.html 多个HtmlWebpackPlugin可以生成不同*.html
        new HtmlWebpackPlugin({
            title: 'Webpack Plugin Sample',
            meta: {
                viewport: 'width=device-width'
            },
            template: "./public/index.html"
            // filename: 'index.html', //指定生成文件名
            // chunks: ['index']
        })
    ],

}

webpack.dev.js 代码演示

const { merge } = require("webpack-merge") //合并其他配置 类似Object.assign()
const commonConfig = require("./webpack.common")
const { DefinePlugin } = require("webpack")

// 开发环境的配置
module.exports = merge(commonConfig, {
    // 这个属性有三种取值,分别是 production、development 和 none。
    // 1. 生产模式下,Webpack 会自动优化打包结果;
    // 2. 开发模式下,Webpack 会自动优化打包速度,添加一些调试过程中的辅助;
    // 3. None 模式下,Webpack 就是运行最原始的打包,不做任何额外处理;
    mode: 'development',
    //指定sourceMap 开发中方便找到源码中错误的位置
    devtool: "#@cheap-module-source-map",
    module: {
        rules: [
            {

                test: /\.(vue|js)$/,
                loader: "eslint-loader",
                exclude: /node_modules/,
                // 预处理
                enforce: "pre"
            },
            {
                //如果use是多个 顺序是从后到前执行 css解析需要style、css loader一起使用
                test: /\.less$/,
                use: ["style-loader", "css-loader", "less-loader"]
            },
            {
                //这个是用来转换vue中的style标签和css文件的
                test: /\.css$/,
                use: ["style-loader", "css-loader"]
            },
        ]
    },
    devServer: {
        contentBase: './public', //指定服务器资源的根目录
        proxy: { //代理 本地解决跨域问题
            '/api': {
                // http://localhost:8080/api/users -> https://api.github.com/api/users
                target: 'https://api.github.com',
                // http://localhost:8080/api/users -> https://api.github.com/users
                pathRewrite: {
                    '^/api': ''
                },
                // 不能使用 localhost:8080 作为请求 GitHub 的主机名
                changeOrigin: true
            }
        },
        port: 9000,
        open: true,  //执行命令时自动打开页面
        hot: true //每次更新资源文件,不用更新所有资源,只更新部分,相当于加了一个补丁
    },
    plugins: [
        new DefinePlugin({
            //定义BASE_URL index.html中需要使用
            BASE_URL: "/public/"
        })
    ]
})

webpack.prod.js 代码演示

const { merge } = require("webpack-merge");
const commonConfig = require("./webpack.common");
const { DefinePlugin, LoaderOptionsPlugin } = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //webpack4.X
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); 
const TerserPlugin = require("terser-webpack-plugin");
const path = require("path");

//生产环境的配置
module.exports = merge(commonConfig, {
    mode: "production",
    //去除sourceMap 防止源码暴露
    devtool: "none",

    //输出的文件名
    output: {
        filename: "js/[name].[hash:8].js",
        publicPath: "./"
    },
    //更改css和less的loader
    module: {
        rules: [
            {
                test: /\.less$/,
                use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"]
            },
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, "css-loader"]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./public/index.html",
            favicon: "./public/favicon.ico", // 在此处设置
            //对html代码进行压缩
            minify: {
                removeComments: true, //去注释
                collapseWhitespace: true, //压缩空格
                removeAttributeQuotes: true //去除属性引用
            }
        }),
        new DefinePlugin({
            BASE_URL: process.env.NODE_ENV
        }),
        //用于每次生成的时候,清理上次的打包文件
        new CleanWebpackPlugin(),
        //主要是为了抽离 css 样式,防止将样式打包在 js 中文件过大和因为文件大网络请求超时的情况 
        new MiniCssExtractPlugin({
            // hash/chunkhash解决缓存
            filename: "css/[name].[hash:7].css",
            chunkname: path.posix.join("static", "css/[id].[chunkhash:7].css")
        })
    ],
    optimization: {
        //代码分包 自动提取所有公共模块到单独包
        splitChunks: {
            chunks: "all"
        },
        minimize: true,
        minimizer: [
            //css压缩
            new OptimizeCSSAssetsPlugin({
                cssProcessorOptions: {
                    discardComments: { remove: true } //移除注释
                }
            }),
            //js优化
            new TerserPlugin({
                parallel: true, //开启多线程来提高构建速度
                sourceMap: false,
                terserOptions: {
                    warnings: false, //不展示warning
                    compress: {
                        unused: true, //去除未使用的
                        drop_debugger: true, //移除debugger
                        drop_console: true //去除console
                    },
                    output: {
                        comments: false //去除注释
                    }
                }
            })
        ]
    }
})

package.json

  "scripts": {
    "serve": "npx webpack-dev-server --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js",
    "lint": "eslint ./src"
  },

webpack 加载资源的方式

1.遵循 ES Modules 标准的 import 声明
2.遵循 CommonJS 标准的 require 函数
3.遵循 AMD 标准的 define 函数和 require 函数
4.样式代码中的 @import 执行和 url 函数
5.HTML 代码中图片标签的 src 属性

Webpack 代码分割

代码分包

所有代码最终都被打包到一起,bundle 体积过大
并不是每个模块在启动时都是必要的
模块打包是必要的,但是应用越来越大之后,需要进行分包,按需加载
有两种方式:多入口打包;ESM 动态导入

多入口打包

常用于多页应用程序
一个页面对应一个打包入口
公共部分单独提取

动态导入

按需加载,需要用到某个模块时,再加载这个模块
可以极大地节省带宽和流量
无需配置任何地方,只需要按照 ESM 动态导入的方式去导入模块,webpack 内部会自动处理分包和按需加载
使用单页应用开发框架(React/Vue),在项目中的路由映射组件就可以通过动态导入实现按需加载

Webpack 魔法注释

使用魔法注释可以为动态导入最终打包出来的文件命名
命名相同的模块最终会被打包到一起

Webpack 输出文件名 Hash

一般我们部署前端资源文件时,都会采用服务器的静态资源缓存
开启缓存的问题:缓存时间过短-效果不明显,缓存过期时间较长-应用发生了更新重新部署后客户端因为缓存得不到更新
解决上面问题,建议生产模式下,文件名使用 Hash,文件名不同也就是新的请求,解决了缓存的问题,服务器可以将缓存过期时间设置足够长

三种 Hash 方式

hash: 整个项目级别的,项目中任意一个地方改动,重新打包之后的 hash 值都会改变
chunkhash: chunk 级别的,同一路的打包 chunkhash 都是相同的
contenthash: 文件级别的hash,根据文件内容生成的hash值,不同的文件就有不同的值
解决缓存问题的最佳 hash 方式 [contenthash:8]

标签:模块化,require,loader,webpack,开发,babel,规范化,js,css
来源: https://blog.csdn.net/weixin_52026514/article/details/112200651

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有