zoukankan      html  css  js  c++  java
  • 前端工程化之webpack

    一、前端工程化

    1、什么是前端工程化?
    前端工程化是指将前端开发的流程规范化、标准化,包括开发流程、技术选型、代码规范、构建发布等,用于提升前端工程师的开发效率和代码质量。

    2、为什么要前端工程化?
    复杂度高:前端项目的多功能、多页面、多状态、多系统
    规模大:团队开发、多人协作,代码质量管理
    要求高:页面性能优化(CDN/异步加载/请求合并),CSS兼容性、单页面应用、服务端渲染...

    3、怎么做前端工程化?
    从业务着手
    简单的单页面应用,使用gulp打包+同步工具实现全流程开发
    从复杂度考虑
    jenkins、git/gilab、webpack、React/Vue/Angular
    从已知向未知扩展
    不同的技术有不同的适应场景,选择合适的才是最好的

    二、前端构建工具

    1、webpack

    1.1 安装

    #环境确认

    nvm install/use v12.16.1
    node -v 
    npm -v

    #快速创建nodejs项目

    npm init -y

    #安装webpack webpack-cli

    #项目安装
    cnpm install webpack webpack-cli -D 或 yarn add webpack webpack-cli -D
    #全局安装
    cnpm install webpack webpack-cli -g 或 yarn add webpack webpack-cli -g

    #查看webpack是否安装成功

    npx webpack --version
    ./node_modules/.bin/webpack --version

    #webpack使用1

    npx webpack XXXX
    或
    ./node_modules/.bin/webpack XXX

    #webpack使用2  #构建修改package.json下面scripts/build 

    {
      "name": "resource",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "build": "webpack"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "webpack": "^5.4.0",
        "webpack-cli": "^4.2.0"
      }
    }

    然后控制台直接执行:

    npm run build 

    1.2五大核心概念

    (1)入口-entry
    单入口webpack配置文件:webpack.config.js

    (2)输出-output
    path使用绝对路径,可以使用path.join拼接路径,nodejs全局变量__dirname(当前目录的绝对路径)
    使用require引入,webstorm需要配置node core

    (3)加载器-loader
    (3.1)转化css文件

    #安装样式loader
    cnpm install css-loader style-loader -D 或yarn add css-loader style-loader -D

    安装完成后,package.json下面的devDependencies会多出两个依赖:

    {
      "name": "resource",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "build": "webpack"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "css-loader": "^5.0.1",
        "style-loader": "^2.0.0",
        "webpack": "^5.4.0",
        "webpack-cli": "^4.2.0"
      }
    }

    #配置使用样式loader打包

    const path=require("path")
    //输出当前目录绝对路径
    console.log(path.resolve())
    //输出当前目录拼接disk的绝对路径
    console.log(path.join(__dirname,'./dist'))
    const config ={
        entry:"./src/index.js",
        output:{
            filename:'bundle.js',//打包后的文件
            path:path.join(__dirname,'./dist')
        },
        module:{
            rules:[
                {
                    test: /.css$/,
                    use: ['style-loader', 'css-loader'] //执行顺序从右到左
                }
            ]
        }
    };
    module.exports=config

    #编写样式src/index.css

    body{
      background: red;
    }

    #index.js引入css

    require('./index.scss')
    console.log("hello webpack!!")

    #打包

    npm run build

    #使用样式 新建./dist/index.html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    hello cac2020
    <script src="bundle.js"></script>
    </body>
    </html>

    #查看结果

    (3.2)一般工程里不会直接编写css样式,而是使用sass、scss预编译css:

    #安装sass-loader node-loader

    yarn add sass-loader node-sass -D

    #webpack设置

    const path=require("path")
    //输出当前目录绝对路径
    console.log(path.resolve())
    //输出当前目录拼接disk的绝对路径
    console.log(path.join(__dirname,'./dist'))
    const config ={
        entry:"./src/index.js",
        output:{
            filename:'bundle.js',//打包后的文件
            path:path.join(__dirname,'./dist')
        },
        module:{
            rules:[
                {
                    test: /.(scss|sass)$/,
                    use: ['style-loader', 'css-loader','sass-loader'] //执行顺序从右到左
                }
            ]
        }
    };
    module.exports=config

    注意一点:loader执行顺序,从右往左

    (4)插件-plugins,提供扩展能力

    支柱功能,解决loader无法实现的其他事情。
    #插件使用示例 HtmlWebpackPlugin(简单创建 HTML 文件,用于服务器访问)

    #安装插件

    yarn add html-webpack-plugin -D

    #配置中引入

    const path=require("path")
    const Htmlwebpackplugin = require("html-webpack-plugin")
    const config ={
        entry:"./src/index.js",
        output:{
            filename:'bundle.js',//打包后的文件
            path:path.join(__dirname,'./dist')
        },
        module:{
            rules:[
                {
                    test: /.(scss|sass)$/,//test用来匹配文件
                    use: ['style-loader', 'css-loader','sass-loader'] //执行顺序从右到左
                }
            ]
        },
        plugins:[
            new Htmlwebpackplugin({
                    filename:"index.html",//生成html的名字
                    template:'template.html'//使用模板html生成html
            }
            )//参数为空 会默认在dist下生成一个普通的index.html
        ]
    
    };
    module.exports=config

    #打包

    npm run build 

    #效果 自动生成dist/index.html,里面会自动引入bundle.js依赖

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title></head>
    <body>hello cac2020
    <script src="bundle.js"></script>
    </body>
    </html>

    #代码热编译

    方式一:热编译:监控自动触发编译
    #修改package.json 监视js是否有变化

    {
      "name": "resource",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "build": "webpack",
        "watch": "webpack --watch"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "css-loader": "^5.0.1",
        "html-webpack-plugin": "^4.5.0",
        "node-sass": "^5.0.0",
        "sass-loader": "^10.1.0",
        "style-loader": "^2.0.0",
        "webpack": "^5.4.0",
        "webpack-cli": "^4.2.0"
      }
    }

    #执行监控

    npm run watch

    #修改index.js保存  在控制台会看到自动执行编译日志

    ...
    [webpack-cli] watching files for updates...
    [webpack-cli] Compilation starting...
    [webpack-cli] Compilation finished
    ...

    #手工刷新页面查看 就会看到更新内容

    方式二:热编译+热刷新
    使用HMR,模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。
    #安装webpack-dev-server,提供开发运行时环境,当有变化时自动刷新浏览器

    yarn add webpack-dev-server -D

    #配置package.json

    {
      "name": "resource",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "build": "webpack",
        "watch": "webpack --watch",
        "hot": "webpack-dev-server"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "css-loader": "^5.0.1",
        "node-sass": "^5.0.0",
        "sass-loader": "^10.1.0",
        "style-loader": "^2.0.0",
        "webpack": "^5.4.0",
        "webpack-cli": "^4.2.0",
        "webpack-dev-server": "^3.11.0"
      }
    }

    #配置webpack.config.js

    const path=require("path")
    const htmlwebpackplugin = require("html-webpack-plugin")
    const webpack = require('webpack')
    const config ={
        entry:"./src/index.js",
        output:{
            filename:'bundle.js',//打包后的文件
            path:path.join(__dirname,'./dist')
        },
        module:{
            rules:[
                {
                    test: /.(scss|sass)$/,
                    use: ['style-loader', 'css-loader','sass-loader'] //执行顺序从右到左
                }
            ]
        },
        devServer:{
            hot: true
        },
        plugins:[
            new htmlwebpackplugin({
                    filename:"index.html",//生成html的名字
                    template:'template.html'//使用模板html生成html
                }),//参数为空 会默认在dist下生成一个普通的index.html
    
            new webpack.HotModuleReplacementPlugin()//初始化HMR
        ]
    
    };
    module.exports=config

    #启动webpack-dev-server

    npm run hot
    E:webappdemo1
    esource>npm run hot                    
    
    > resource@1.0.0 hot E:webappdemo1
    esource
    > webpack-dev-server
    
    i 「wds」: Project is running at http://localhost:8080/
    i 「wds」: webpack output is served from /
    i 「wds」: Content not from webpack is served from E:webappdemo1
    esource
    i 「wdm」: Hash: fb2be21415c83bcbde26
    Version: webpack 4.35.2
    Time: 727ms
    Built at: 2020-11-12 1:24:03 PM
         Asset       Size  Chunks             Chunk Names
     bundle.js    406 KiB    main  [emitted]  main
    index.html  182 bytes          [emitted]  
    Entrypoint main = bundle.js
    [0] multi (webpack)-dev-server/client?http://localhost (webpack)/hot/dev-server.js ./src/index.js 52 bytes {main} [built]
    [./node_modules/strip-ansi/index.js] 161 bytes {main} [built]
    [./node_modules/webpack-dev-server/client/index.js?http://localhost] (webpack)-dev-server/client?http://localhost 4.29 KiB
    {main} [built]
    [./node_modules/webpack-dev-server/client/overlay.js] (webpack)-dev-server/client/overlay.js 3.51 KiB {main} [built]
    [./node_modules/webpack-dev-server/client/socket.js] (webpack)-dev-server/client/socket.js 1.53 KiB {main} [built]
    [./node_modules/webpack-dev-server/client/utils/createSocketUrl.js] (webpack)-dev-server/client/utils/createSocketUrl.js 2.
    77 KiB {main} [built]
    [./node_modules/webpack-dev-server/client/utils/log.js] (webpack)-dev-server/client/utils/log.js 964 bytes {main} [built]
    [./node_modules/webpack-dev-server/client/utils/reloadApp.js] (webpack)-dev-server/client/utils/reloadApp.js 1.63 KiB {main
    } [built]
    [./node_modules/webpack-dev-server/client/utils/sendMessage.js] (webpack)-dev-server/client/utils/sendMessage.js 402 bytes
    {main} [built]
    [./node_modules/webpack/hot sync ^./log$] (webpack)/hot sync nonrecursive ^./log$ 170 bytes {main} [built]
    [./node_modules/webpack/hot/dev-server.js] (webpack)/hot/dev-server.js 1.59 KiB {main} [built]
    [./node_modules/webpack/hot/emitter.js] (webpack)/hot/emitter.js 75 bytes {main} [built]
    [./node_modules/webpack/hot/log-apply-result.js] (webpack)/hot/log-apply-result.js 1.27 KiB {main} [built]
    [./node_modules/webpack/hot/log.js] (webpack)/hot/log.js 1.34 KiB {main} [built]
    [./src/index.js] 58 bytes {main} [built]
        + 24 hidden modules
    Child HtmlWebpackCompiler:
         1 asset
        Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
        [./node_modules/html-webpack-plugin/lib/loader.js!./template.html] 403 bytes {HtmlWebpackPlugin_0} [built]
    i 「wdm」: Compiled successfully.
    View Code

    可以看到访问:http://localhost:8080/ 即可查看

    执行的时候可能报错:

    0 info it worked if it ends with ok
    1 verbose cli [
    1 verbose cli   'C:\Program Files\nodejs\node.exe',
    1 verbose cli   'C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js',
    1 verbose cli   'run',
    1 verbose cli   'hot'
    1 verbose cli ]
    2 info using npm@6.13.4
    3 info using node@v12.16.1
    4 verbose run-script [ 'prehot', 'hot', 'posthot' ]
    5 info lifecycle resource@1.0.0~prehot: resource@1.0.0
    6 info lifecycle resource@1.0.0~hot: resource@1.0.0
    7 verbose lifecycle resource@1.0.0~hot: unsafe-perm in lifecycle true
    8 verbose lifecycle resource@1.0.0~hot: PATH: C:UsersAdministratorAppDataRoaming
    vmv12.16.1
    ode_modules
    pm
    ode_modules
    pm-lifecycle
    ode-gyp-bin;E:webappdemo1
    esource
    ode_modules.bin;C:Program Files (x86)Common FilesNetSarang;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;C:Program FilesTortoiseSVNin;C:javajdk1.8.0_171in;C:javajdk1.8.0_171jrein;D:apache-maven-3.6.1in;D:apache-maven-3.6.1in;D:Gitcmd;C:Python27;D:mongoDB4.0in;D:mysql-5.6.45-winx64in;C:erl10.5in;C:RabbitMQServer
    abbitmq_server-3.7.17sbin;D:gradle-4.6/bin;D:apache-ant-1.10.7/bin;D:sonar-scanner-4.2.0.1873/bin;C:Program Files (x86)Pandoc;C:UsersAdministratorAppDataRoaming
    vm;C:Program Files
    odejs;C:Program Files (x86)Yarnin;D:VSCodein;C:UsersAdministratorAppDataLocalGitHubDesktopin;C:UsersAdministratorAppDataRoaming
    vm;C:Program Files
    odejs;C:UsersAdministratorAppDataLocalYarnin
    9 verbose lifecycle resource@1.0.0~hot: CWD: E:webappdemo1
    esource
    10 silly lifecycle resource@1.0.0~hot: Args: [ '/d /s /c', 'webpack-dev-server' ]
    11 silly lifecycle resource@1.0.0~hot: Returned: code: 1  signal: null
    12 info lifecycle resource@1.0.0~hot: Failed to exec hot script
    13 verbose stack Error: resource@1.0.0 hot: `webpack-dev-server`
    13 verbose stack Exit status 1
    13 verbose stack     at EventEmitter.<anonymous> (C:UsersAdministratorAppDataRoaming
    vmv12.16.1
    ode_modules
    pm
    ode_modules
    pm-lifecycleindex.js:332:16)
    13 verbose stack     at EventEmitter.emit (events.js:311:20)
    13 verbose stack     at ChildProcess.<anonymous> (C:UsersAdministratorAppDataRoaming
    vmv12.16.1
    ode_modules
    pm
    ode_modules
    pm-lifecyclelibspawn.js:55:14)
    13 verbose stack     at ChildProcess.emit (events.js:311:20)
    13 verbose stack     at maybeClose (internal/child_process.js:1021:16)
    13 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5)
    14 verbose pkgid resource@1.0.0
    15 verbose cwd E:webappdemo1
    esource
    16 verbose Windows_NT 6.1.7601
    17 verbose argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "run" "hot"
    18 verbose node v12.16.1
    19 verbose npm  v6.13.4
    20 error code ELIFECYCLE
    21 error errno 1
    22 error resource@1.0.0 hot: `webpack-dev-server`
    22 error Exit status 1
    23 error Failed at the resource@1.0.0 hot script.
    23 error This is probably not a problem with npm. There is likely additional logging output above.
    24 verbose exit [ 1, true ]
    View Code

    原因:webpack和webpack-dev-server版本不兼容
    解决方案:卸载原来版本 下载兼容版本即可

    #卸载
    yarn remove webpack webpack-cli webpack-dev-server -D  或 cnpm uninstall webpack webpack-cli webpack-dev-server -D
    #安装指定版本
    yarn add webpack@4.35.2 webpack-cli@3.3.5 webpack-dev-server@3.7.2 -D 或 cnpm i webpack@4.35.2 webpack-cli@3.3.5 webpack-dev-server@3.7.2 -D

    参考:
    webpack-dev-server

    ****几个常用插件*****
    clean-webpack-plugin 清理插件
    copy-webpack-plugin 拷贝插件
    optimize-css-assets-webpack-plugin css压缩插件
    terser-webpack-plugin js压缩插件
    mini-css-extract-plugin 在html头部单独引用CSS样式文件的压缩插件
    适配版本:

    yarn add clean-webpack-plugin@3.0.0 copy-webpack-plugin@5.0.3 optimize-css-assets-webpack-plugin terser-webpack-plugin@1.3.0 mini-css-extract-plugin@1.3.0 -D

    webpack.config.js:

    const path=require("path")
    const HtmlWebpackPlugin = require("html-webpack-plugin")
    const webpack = require('webpack')
    //清理插件的定义比较特殊 使用{} 前后有空格
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    const CopyWebpackPlugin = require('copy-webpack-plugin')
    const MiniCssExtractPlugin  = require('mini-css-extract-plugin')
    const TerserJSPlugin = require('terser-webpack-plugin')
    const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
    
    const config ={
        mode:'production',
        entry:"./src/index.js",
        output:{
            filename:'bundle.js',//打包后的文件
            path:path.join(__dirname,'./dist')
        },
        //optimization  压缩配置
        optimization:{
            minimizer:[new TerserJSPlugin({}),new OptimizeCSSAssetsPlugin({})],
        },
        module:{
            rules:[
                {
                    test: /.(scss|sass)$/,
                    use: [MiniCssExtractPlugin.loader, 'css-loader','sass-loader'] //执行顺序从右到左
                },
                {
                    test:/.js$/,
                    loader:'babel-loader'
                }
            ]
        },
        devServer:{
            hot: true
        },
        plugins:[
            new HtmlWebpackPlugin({
                    filename:"index.html",//生成html的名字
                    template:'template.html'//使用模板html生成html
                }),//参数为空 会默认在dist下生成一个普通的index.html
    
            new webpack.HotModuleReplacementPlugin(),//初始化HMR
            new CleanWebpackPlugin(),
            new CopyWebpackPlugin([
                {
                    from: path.join(__dirname, 'assets'),
                    to: 'assets'
                }
            ]),
            //MiniCssExtractPlugin会把样式单独提取出来放到一个css文件被html引用
            new MiniCssExtractPlugin({
                filename:'[name].css',
                chunkFilename:'[id].css'
            })
        ]
    };
    module.exports=config

    (5)模式/兼容性

    模式-mode:将process.env.NODE_ENV设置为开发模式-development和产品模式production,不同模式webpack会启用不同的插件,比如production模式下会启用压缩、混淆插件。
    #webpack.config.js配置:

    const path=require("path")
    const htmlwebpackplugin = require("html-webpack-plugin")
    const webpack = require('webpack')
    const config ={
        mode:'development',
        entry:"./src/index.js",
        output:{
            filename:'bundle.js',//打包后的文件
            path:path.join(__dirname,'./dist')
        },
        module:{
            rules:[
                {
                    test: /.(scss|sass)$/,
                    use: ['style-loader', 'css-loader','sass-loader'] //执行顺序从右到左
                }
            ]
        },
        devServer:{
            hot: true
        },
        plugins:[
            new htmlwebpackplugin({
                    filename:"index.html",//生成html的名字
                    template:'template.html'//使用模板html生成html
                }),//参数为空 会默认在dist下生成一个普通的index.html
    
            new webpack.HotModuleReplacementPlugin()//初始化HMR
        ]
    
    };
    module.exports=config

    #process.env.NODE_ENV的使用
    #修改index.js

    require('./index.scss')
    console.log("hello webpack!! Ok")
    
    if(process.env.NODE_ENV == 'development'){
        console.log("baseurl is localhost!")
    }
    else{
        console.log("baseurl is cac2020.com!")
    }

    loader与plugins区别:

    loader去转化webpack不能处理的文件类型,也就是除了js以外的文件,转化为webpack能够处理的文件。
    plugins;扩展更复杂的构建任务功能。

    1.3 babel
    Babel是一个JavaScript编译器,可以将最新版的javascript编译成当下可以执行的版本,简言之,利用babel就可以让我们在当前的项目中随意的使用这些新最新的es6,甚至es7的语法。说白了就是把各种javascript千奇百怪的语言统统专为浏览器可以认识的语言。
    #安装babel

    yarn add babel-loader@8.0.6 @babel/core@7.5.0 @babel/preset-env@7.5.0 @babel/plugin-transform-runtime@7.5.0 -D

    #在生产环境中提供babel运行时

    yarn add @babel/runtime@7.5.1 -S  

    #新增babel配置文件 .babelrc  配置babel转换运行时插件等

    {
      "presets": [
        "@babel/preset-env"
      ],
      "plugins": [
        "@babel/plugin-transform-runtime"
      ]
    }

    #编辑配置文件webpack.config.js

    const path=require("path")
    const HtmlWebpackPlugin = require("html-webpack-plugin")
    const webpack = require('webpack')
    //清理插件的定义比较特殊 使用{} 前后有空格
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    const CopyWebpackPlugin = require('copy-webpack-plugin')
    const MiniCssExtractPlugin  = require('mini-css-extract-plugin')
    const TerserJSPlugin = require('terser-webpack-plugin')
    const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
    
    const config ={
        mode:'production',
        entry:"./src/index.js",
        output:{
            filename:'bundle.js',//打包后的文件
            path:path.join(__dirname,'./dist')
        },
        //optimization  压缩配置
        optimization:{
            minimizer:[new TerserJSPlugin({}),new OptimizeCSSAssetsPlugin({})],
        },
        module:{
            rules:[
                {
                    test: /.(scss|sass)$/,
                    use: [MiniCssExtractPlugin.loader, 'css-loader','sass-loader'] //执行顺序从右到左
                },
                {
                    test:/.js$/,
                    loader:'babel-loader'
                }
            ]
        },
        devServer:{
            hot: true
        },
        plugins:[
            new HtmlWebpackPlugin({
                    filename:"index.html",//生成html的名字
                    template:'template.html'//使用模板html生成html
                }),//参数为空 会默认在dist下生成一个普通的index.html
    
            new webpack.HotModuleReplacementPlugin(),//初始化HMR
            new CleanWebpackPlugin(),
            new CopyWebpackPlugin([
                {
                    from: path.join(__dirname, 'assets'),
                    to: 'assets'
                }
            ]),
            //MiniCssExtractPlugin会把样式单独提取出来放到一个css文件被html引用
            new MiniCssExtractPlugin({
                filename:'[name].css',
                chunkFilename:'[id].css'
            })
        ]
    };
    module.exports=config

    #写一个ES6语法的a.js

    export default ()=> {
        console.log('hello from module a')
    }

    #在index.js引用

    import('./index.scss')
    //从a.js引入afn
    import afn from './a'
    //执行afn
    afn()
    
    console.log("hello webpack!! Ok")
    
    if(process.env.NODE_ENV == 'development'){
        console.log("baseurl is localhost!")
    }
    else{
        console.log("baseurl is cac2020.com!")
    }

    工程目录参考:

    参考:
    webpack官网 
    webpack中文文档

  • 相关阅读:
    HIVE之 Sqoop 1.4.6 安装、hive与oracle表互导
    Sqoop之 Sqoop 1.4.6 安装
    PIG之 Hadoop 2.7.4 + pig-0.17.0 安装
    hadoop之 node manager起不来, 执行mapreduce 程序hang住
    Maven 简介
    graphviz 的节点形状
    graphviz 的绘图布局
    Graphviz 的命令行参数说明
    golang使用graphviz
    IDEA 项目相关基础设置
  • 原文地址:https://www.cnblogs.com/cac2020/p/13958358.html
Copyright © 2011-2022 走看看