webpack随笔

webpack

介绍

webpack是个工具,协助开发者做项目管理、打包、模块管理、加载资源,并转换到对应环境,webpack是一种静态编译工具(预编译),官网中文国内

资源: js/css/html/png…/woff/data/vue…

转换:loader

前身

grunt->gulp->browserify->webpack->??

历史

  • webpack1 支持CMD和AMD,同时拥有丰富的plugin和loader,webpack逐渐得到广泛应用。
  • webpack2 支持ES Module,分析ESModule之间的依赖关系,webpack1必须将ES,Module转换成CommonJS模块,2支持tree sharking

tree sharking: 优化功能,顾名思义,就是将多余的代码给 “摇晃” 掉,在开发中我们经常使用一些第三方库,而这些第三方库只使用了这个库的一部门功能或代码,未使用的代码也要被打包进来,这样出口文件会非常大,tree-sharking 帮我们解决了这个问题,它可以将各个模块中没有使用的方法过滤掉,只对有效代码进行打包

  • webpack3 新的特性大都围绕ES Module提出,如Scope Hoisting和Magic Comment

    Scope Hoisting: 可以让 Webpack 打包出来的代码文件更小、运行的更快,它又译作 “作用域提升”,是在 Webpack3 中新推出的功能

Magic Comment: 魔法注释(magic comment)修改打包动态组件名称

weback5

  • 尝试用持久性缓存来提高构建性能。
  • 尝试用更好的算法和默认值来改进长期缓存。
  • 尝试用更好的 Tree Shaking 和代码生成来改善包大小。
  • 尝试改善与网络平台的兼容性。
  • 尝试在不引入任何破坏性变化的情况下,清理那些在实现 v4 功能时处于奇怪状态的内部结构。
  • 试图通过现在引入突破性的变化来为未来的功能做准备,使其能够尽可能长时间地保持在 v5 版本上

目标

模块化,工程化(环境分离),自动化我们的开发环境,涉及到的知识点有入口、出口、转换器、插件

development:
a.浏览器调试工具
b.注释、开发阶段的详细错误日志和提示
c.快速和优化的增量构建机制
production:
a.开启所有的优化代码
b.更小的main大小
c.去除掉只在开发阶段运行的代码
d.Scope hoisting(作用域提升)和Tree-shaking(打包的结构只包含实际用到的 exports)

环境要求

webpack4/5 :Node8+/10、npm5+/6

单页(spa) VS 多页(mpa)

页面模式多页面模式(MPA Multi-page Application)单页面模式(SPA Single-page Application)
页面组成多个完整页面, 例如page1.html、page2.html等由一个初始页面和多个页面模块组成, 例如:index.html
公共文件加载跳转页面前后,js/css/img等公用文件重新加载js/css/img等公用文件只在加载初始页面时加载,更换页面内容前后无需重新加载
页面跳转/内容更新页面通过window.location.href = "./page2.html"跳转通过使用js方法,append/remove或者show/hide等方式来进行页面内容的更换
数据的传递可以使用路径携带数据传递的方式,例如:http://index.html?account=“123”&password=123456"",或者localstorage、cookie等存储方式直接通过参数传递,或者全局变量的方式进行,因为都是在一个页面的脚本环境下
用户体验如果页面加载的文件相对较大(多),页面切换加载会很慢页面片段间切换较快,用户体验好,因为初次已经加载好相关文件。但是初次加载页面时需要调整优化,因为加载文件较多
场景适用于高度追求高度支持搜索引擎的应用高要求的体验度,追求界面流畅的应用
转场动画不容易实现容易实现

单页面模式:相对比较有优势,无论在用户体验还是页面切换的数据传递、页面切换动画,都可以有比较大的操作空间 多页面模式:比较适用于页面跳转较少,数据传递较少的项目中开发,否则使用cookie,localstorage进行数据传递,是一件很可怕而又不稳定的无奈选择

SPA

安装

全局环境

npm i webpack webpack-cli -g

项目环境

npm i webpack webpack-cli --save-dev

打包

执行:  webpack 
//默认 会自动找src/index.js 到 dist/main.js

//要求设置开发模式|生产模式
执行:  webpack --mode development | production

//指定出入口
webpack 入口地址 --mode development  指定出口   ***

依赖

Webpack 会分析入口文件,解析包含依赖关系的各个文件。这些文件(模块)都打包到 main.js 。Webpack 会给每个模块分配一个唯一的 id 并通过这个 id 索引和访问模块。在页面启动时,会先执行 main.js 中的代码,其它模块会在运行 require 的时候再执行。

loader

类似一种转化器, 它可以把一个东西,转成另一个,webpack默认只支持javascript文件模块化,其他文件如需模块化,需要转换器(loader,加载器),loader都需要安装

style-loader

编译好的css文件插到页面

css-loader

读取css文件,模块化

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

把模块化引入的文件,转换base64

file-loader

模块化引入文件

{
  test: /\.(png|jpg|gif)$/i,
  use: [
    {
      loader: 'url-loader',
      options: {
        limit: 5000,
        // outputPath:'images/',//大于5000字节,引文件
        name:'images/[name]-[hash:8].[ext]'
      }
    }
  ]
}
babel-loader

优雅降级, es6+ 转换 es5,与他同款还有trcuer

安装

npm install babel-loader @babel/core @babel/preset-env -D

@babel/core 核心

@babel/preset-env 解析目标 es6+ 包

配置

webpack .config

module.exports = {
  module:{
    rules:[
      {
        test:/\.js$/,
        exclude:/node_modules/, 排除
        use:[{
          loader:'babel-loader',
          options:{ //相关配置 可以配置在webpack.config 亦可以配置在.bablerc
            presets: ['@babel/preset-env']
          }
        }]
      }	
    ]
  }
}

.babelrc

{
  "presets": [
    "@babel/preset-env"
  ]
}

配置

命令式

webpack 入口地址 --mode development  指定出口  权重最高

coding

require('style-loader!css-loader!./assets/css/base.css')

配置文件

webpack.config.js 出现在项目根(package.json所在的位置),webpack也可以依赖的第三方的配置文件(bablerc),webpack的配置文件是一个nodejs文件

//是一个nodejs
let path = require('path');

module.exports = {
  //入口
  entry: './src/main.js',//string object

  //出口
  output: {//要求必须是个对象,path的值一定要是磁盘路径
    path: path.join(__dirname, 'dist'),
    publicPath: '/', //公共路径
    filename: 'js/app.js'//输出后的文件名
  },

  //模块
  module: {
    rules: [
      { test: /\.css$/, use: ['style-loader', 'css-loader'] }
    ]
  },
  
  //模式
  mode: 'production', //production  区别环境
}

webpack-dev-server

搭建前端开发环境服务器,可以在开发环境下,浏览器热刷新,模块热重载(增量构建机制),默认自动打包(放到内存),创建前端开发型服务器(默认找webpack.config所在的位置,找index.html),资源查找先找内存,之后是磁盘

配置

//scripts 命令行
"scripts": {
    "start": "webpack serve --port 8080 --open --mode development"
  },
//webpack.config.js配置文件
devServer:{
    port: 8081,//端口
    open: false, //开浏览器
    // contentBase: path.join(__dirname,'public'), //静态资源|html 托管位置
    inline:true, //浏览器热刷新
    // host:'127.0.0.1'  //主机地址
    // https: false , //开启https服务器,需要提供签名文件
    // progress: true, //开启打包进度
    overlay: true, //浏览器中显示全屏覆盖层。显示编译器错误  V5 有问题
    proxy:{
      '/api':{
        target:'http://localhost:9001',
        /* pathRewrite:{
          '^/api': ''
        } */
      },
      '/douban':{
        target:'https://douban.uieee.com',
        pathRewrite:{
          '^/douban':''
        },
        secure: false //接受https的代理
      }
    },
    // watchContentBase: true, //监听public下的文件变动
  }

devtool

代码错误没有报到正确位置,使用devtool,把代码错误指定到src源代码中

module.exports={
  devtool:'inline-source-map'
}

resolve

定义文件名后缀,省略引入时输入后缀

module.exports={
  resolve:{
    extensions:['.js','.css','.json','.jsx','.vue']
  }
}

定义别名

module.exports={
  resolve:{
    alias:{
      '@': path.resolve(__dirname,'src'),
      '~': path.resolve(__dirname,'public')
    }
  }
}

插件

插件就是一个类|工厂方法,使用需要安装,引入在plugins选项里面实例化

html-webpack-plugin

产出html,动态给html做拷贝,及注入的工作

安装

npm i html-webpack-plugin -S

引入

//webpack.config
var HtmlWebpackPlugin = require('html-webpack-plugin');//插件==类

配置plugins

module.exports = {
  plugins:[
    new HtmlWebpackPlugin({
      // title:'HTML标题',//html 浏览器的标题
      filename:'index.html',//输出到dist的文件名
      template:'./public/index.html',//要参考的html模板
      hash:true, //防止缓存,会给文件后面加入hash
      minify:{
        //是否去除空格,默认false
        collapseWhitespace: true,
        
        //是否压缩html里的css(使用clean-css进行的压缩) 默认值false;
        minifyCSS: true,
        
        //是否压缩html里的js(使用uglify-js进行的压缩)
        minifyJS: true,
        
        //是否移除注释 默认false
        removeComments: true,
      },
      favicon:'./public/favicon.ico',//配置网址图标
    })
  ]
}

filename 参考 output配置

extract-text-webpack-plugin

css抽离

//npm i extract-text-webpack-plugin@next -D
module.exports = {
  module:{
    rules:[
      /* { 
        test: /\.css$/, 
        use: ['style-loader', 'css-loader'] 
      }, */
      { 
        test: /\.css$/, 
        use:  ExtractTextWebapckPlugin.extract({ // 接管style-loader
          use:'css-loader'
        })
      },
    ]
  },
  plugins:[
    new ExtractTextWebapckPlugin('css/[name][hash:6].css') //指向dist下面的css目录
  ]
}
mini-css-extract-plugin

css抽离

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/[name]-[hash:3].css",//设定抽离的css存放位置,和文件名
      //chunkFilename: "[id].css"//设置片id
    })
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
         	MiniCssExtractPlugin.loader,
          "css-loader"
        ]
      }
    ]
  }
}
copy-webpack-plugin

资源copy,静态资源(js,数据图片,json) 拷贝到部署环境(生产环境)

const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
  plugins:[
    new CopyWebpackPlugin({
      patterns: [
        { from: path.resolve(__dirname,'public'), to: path.resolve(__dirname,'dist/static')  },
      ],
    })
  ]
}
transfer-webpack-plugin

资源copy,静态资源(js,数据图片,json) 拷贝到部署环境(生产环境)

new TransferWebpackPlugin([//转移文件的插件
      {
        from: 'assets',
        to: 'assets'
      }
    ], path.resolve(__dirname, "src"))
ProvidePlugin

webpack系统插件,自动加载模块,而不必到处 importrequire

const webpack = require('webpack')

module.exports = {
  plugins:[
    new webpack.ProvidePlugin({
      $: 'jquery',
      axios: 'axios'
    })
  ]
}
clean-webpack-plugin
//打包前,清除 dist | build 目录
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  plugins:[
    new CleanWebpackPlugin.CleanWebpackPlugin()//清理output指定的 文件夹,在每次打包之前
  ]
}
SplitChunkPlugin 分片打包
//公共模块拆分  分片打包
  optimization: {
    //提取公共模块,webpack4去除了CommonsChunkPlugin,使用SplitChunksPlugin作为替代
    splitChunks: {
      // 表示显示块的范围,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为all;
      chunks: "all",
      // 表示在压缩前的最小模块大小,默认为0;
      minSize: 30000,
      //表示被引用次数,默认为1
      minChunks: 1,
      //最大的按需(异步)加载次数,默认为1;
      maxAsyncRequests: 3,
      //最大的初始化加载次数,默认为1;
      maxInitialRequests: 3,
      // 拆分出来块的名字(Chunk Names),默认由块名和hash值自动生成;设置ture则使用默认值
      name: true,
      
      //缓存组,目前在项目中设置cacheGroup可以抽取公共模块,不设置则不会抽取
      cacheGroups: {
        //缓存组信息,名称可以自己定义
        app: {
          //拆分出来块的名字,默认是缓存组名称+"~" + [name].js
          name: "app",
          // 同上
          chunks: "all",
          // 同上
          minChunks: 3,
          // 如果cacheGroup中没有设置minSize,则据此判断是否使用上层的minSize,true:则使用0,false:使用上层minSize
          enforce: true,
          //test: 缓存组的规则,表示符合条件的的放入当前缓存组,值可以是function、boolean、string、RegExp,默认为空;
          test: /src/
        },

        //设置多个缓存规则
        vendor: {
          test: /node_modules/,
          chunks: "all",
          name: "vendor",
          //表示缓存的优先级
          priority: 10,
          enforce: true
        }
      }

    }

  }

参考

配置文件分离

不同的环境(开发,生产,测试),不同的配置文件(dev,prod,test)

物料: webpack-merge 给不同环境合并进去一些公共配置(common|base)

//package.json
//设定 webpack.config -> webpack.config.dev|prod|common|test
"scripts": {
  "build": "webpack --mode production --config webpack.config.prod",
  "start": "webpack-dev-server --mode development --config webpack.config.dev",
  "test": "webpack-dev-server --mode development --config webpack.config.test",
  "server": "pm2 start ./xxx --name=8080node --watch"
},

SPA for VUE

基本物料

vue 核心包

vue-loader 支持vue单文件组件

vue-template-compiler 编译时使用

webpack 工具

webpack-dev-server 开发服务器

可选

style-loader | vue-style-loader 把样式插入到style标签

sass-loader node-sass 支持scss

bable-loader | @babel/core | @babel-preset-env 支持es6+

url-loader | file-loader 文件优化

配置

官方指引

问题

  • 处理资源路径:前景图片 相对路径
  • 支持 async await
  • css模块化: 开启模块化会影响所有vue文件

SPA FOR REACT

一、 初始化项目

  • 创建项目目录
  • 初始化 yarn 项目
yarn init -y
  • 初始化 git 项目
# 初始化项目
git init

# 添加 .gitignore
echo "/node_modules\n/build" >> .gitignore

# 关联远程仓库
git remote add origin <url>

二、 Webpack 配置

2.1 基础配置设置
  • 创建文件 /src/index.js作为 webpack 的入口文件
import React from 'react';
import reactDom from 'react-dom';

const App = () => (
  <div>
    test page
  </div>
);
reactDom.render(<App/>, document.getElementById('root'));
  • 创建模板文件 /public/index.htmlwebpack 打包后的文件将添加到该文件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</meta></meta></head>
<body>
  <div id="root"></div>
</body>
</html>

  • 创建 webpack开发环境下配置文件 /config/webpack.config.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const htmlWebpackPlugin = new HtmlWebpackPlugin({
  template: path.resolve(__dirname, '../public/index.html'),
});

module.exports = {
  mode: 'development',                              
  entry: path.resolve(__dirname, '../src/index.js'),
  output: {                                         
    path: path.resolve(__dirname, '../build'),      
    filename: 'js/[name].[hash].bundle.js',         
  },
  module: {
    rules: [              
      {
        test: /\.(mjs|js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      }
    ],
  },

  plugins: [
    htmlWebpackPlugin,
  ],

  resolve: {
    extensions: ['.mjs', '.js', '.jsx'],
  },
};

  • 创建 webpack生产环境下配置文件 /config/webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const htmlWebpackPlugin = new HtmlWebpackPlugin({
  template: path.resolve(__dirname, '../public/index.html'),
});

module.exports = {
  mode: 'production',  // 和开发环境下的配置只是修改了 mode                            
  entry: path.resolve(__dirname, '../src/index.js'),
  output: {                                         
    path: path.resolve(__dirname, '../build'),      
    filename: 'js/[name].[hash].bundle.js',         
  },
  module: {
    rules: [              
      {
        test: /\.(mjs|js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      }
    ],
  },

  plugins: [
    htmlWebpackPlugin,
  ],

  resolve: {
    extensions: ['.mjs', '.js', '.jsx'],
  },
};

  • 创建 babel配置文件 .babelrc
{
  "presets": [
    "@babel/preset-react",
    "@babel/preset-env"
  ]
}

  • 修改 package.json: 添加 npm 脚本
"scripts": {
+  "start": "webpack-dev-server --config ./webpack/webpack.config.dev.js --open",
+  "build": webpack --config ./webpack/webpack.config.prod.js"
}

2.2 安装基础插件包

webpack 相关依赖包、插件

  • webpack: webpack 基础包
  • webpack-cli: webpack cli 工具包
  • html-webpack-plugin: webpack 插件, 用于将打包后的文件添加到指定的 html 内
  • webpack-dev-server: webpack 开发环境工具, 创建一个开发环境
  • babel-loader: webpack loader, 用于编译打包 js 文件
  • @babel/core: babel 依赖包, 将 js 代码分析成 ast
  • @babel/preset-react: webpack react 相关预设
  • @babel/preset-env: weboack react 相关预设, 这样就可以使用最新的 js 相关语法
yarn add webpack webpack-cli html-webpack-plugin webpack-dev-server babel-loader @babel/core @babel/preset-react @babel/preset-env --save-dev

react 相关依赖包

  • react
  • react-dom
yarn add react react-dom --save

2.3 测试
  1. 执行 yarn start测试项目是否能够正常运行
  2. 执行 yarn build测试是否能够正常对项目进行打包、编译, 编译后目录结构如下
.
├── index.html
└── js
    └── main.0b16f9b82b7fb2c9ba47.bundle.js

2.4 总结

到这里一个最基本的 React 项目就已经搭建起来了, 但如果只是这些配置简单配置肯定是远远不够的, 上面只是为了说明其实要搭建一个 React 基础项目还是很简单的, 剩下的工作就是不断的根据具体需求扩充项目配置。下面开始会简单根据需要对项目的配置进行扩展, 比如:

  • webpack 添加对 scss 样式文件的解析
  • webpack 添加对图片的解析
  • 项目添加 eslint 配置
  • 项目添加版本发布、git commit 规范配置
  • 项目添加对 antd 的支持, 并配置按需加载模块

三、 添加对 scss 样式文件的支持

3.1 TODO
  1. 添加对 css 样式文件的支持
  2. 添加对 scss 样式文件的支持
  3. 使用 mini-css-extract-plugin 将 css抽离
  4. 添加 css 模块化的支持, 对 .module.css``.module.scss的样式文件启用模块化
3.2 webpack 配置修改
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin');

+ const miniCssExtractPlugin = new MiniCssExtractPlugin({
+   filename: 'style/[name].[hash].css',
+   chunkFilename: 'style/[id].[hash].css',
+ });

+ const cssRegex = /\.(css|scss)$/;
+ const cssModuleRegex = /\.module\.(css|scss)$/;

module.exports = {
  module: {
    rules: [              
+     {
+       test: cssRegex,
+       exclude: cssModuleRegex,
+       sideEffects: true,
+       use: [
+         {
+           loader: MiniCssExtractPlugin.loader,
+           options: {
+             hmr: process.env.NODE_ENV === 'development',
+           },
+         },
+         { loader: 'css-loader', options: { importLoaders: 1 } },
+         'sass-loader',
+       ],
+     },
+     {
+       test: cssModuleRegex,
+       use: [
+         {
+           loader: MiniCssExtractPlugin.loader,
+           options: {
+             hmr: process.env.NODE_ENV === 'development',
+           },
+         },
+         {
+           loader: 'css-loader',
+           options: {
+             modules: {
+               localIdentName: '[local]__[hash:base64]',
+             },
+           },
+         },
+         'sass-loader',
+       ],
+     }
    ],
  },

  plugins: [
+   miniCssExtractPlugin,
  ],
};

3.3 安装依赖
  • css-loader
  • sass-loader
  • node-sass
  • mini-css-extract-plugin
yarn add mini-css-extract-plugin css-loader sass-loader node-sass --save-dev

3.4 代码测试

创建 src/index.css

.css {
  padding-top: 20px;
}

创建 src/index.module.css

.module-css {
  padding-right: 20px;
}

创建 src/index.scss

.scss {
  padding-bottom: 20px;
}

创建 src/index.module.scss

.module-scss {
  padding-left: 20px;
}

修改 src/index.js

import React from 'react';
import reactDom from 'react-dom';
+ import css from './index.module.css';
+ import scss from './index.module.scss';
+ import './index.css';
+ import './index.scss';

const App = () => (
+ <div className="{`" +="" css="" scss="" ${css['module-css']}="" ${scss['module-scss']}="" `}="">
    test page
  </div>
);
reactDom.render(<App/>, document.getElementById('root'));

运行项目测试样式是否正确加载

四、 添加对图片的支持

这里其实没什么好讲的, 主要使用 url-loader对图片进行处理, 需要特别注意的是该插件依赖于 file-loader

4.1 webpack 修改
module.exports = {
  module: {
    rules: [              
+     {
+       test: /\.(png|jpg|gif|woff|svg|eot|ttf)$/,
+       use: [{
+         loader: 'url-loader',
+         options: {
+           limit: 10000,
+           name: 'assets/[hash].[ext]',
+         },
+       }],
+     },
    ],
  },
};

4.2 依赖安装
yarn add url-loader file-loader --save-dev

4.3 测试

没什么好说的, 找一张图片在 src/index.js中引用看是否能够正常显示即可

import React from 'react';
import reactDom from 'react-dom';
import Img from './1519971416-JDHjSqWCph.jpg';

const App = () => (
  <div>
    <img src="{Img}"/>
  </div>
);
reactDom.render(<App/>, document.getElementById('root'));

五、 esling 配置

5.1 webpack 配置修改

这里只需在 babel-loader之后添加 eslint-loader, 需要特别注意的是它们的顺序

module.exports = {
  module: {
    rules: [  
      {
        test: /\.(mjs|js|jsx)$/,
        exclude: /node_modules/,
+       use: ['babel-loader', 'eslint-loader'],
      },
    ],
  },
};

5.2 项目下添加 .eslintrc.js配置文件
module.exports = {
  parser: 'babel-eslint',
  // 开发环境设置: 在使用下拉环境中的全局变量时不会因为未定义变量而报错, 如 window
  env: {
    browser: true,          
    node: true     
  },

  // 定义全局变量, 在直接使用下列全局变量情况下不会因为未定义变量而报错
  globals: {
    _: true,
    lodash: true,
  },

  // 插件列表
  plugins: [
    'react',
    'import',
    'react-hooks',
  ],

  // 继承的规则
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
  ],

  // 自定义规则列表  
  rules: {
    // 强制在每个语句后面使用分号
    "semi": [1, "always"], 
  }
}

5.3 项目下添加 .eslintignore
# 设置需要忽略的文件
/src/assets/*

5.4 安装依赖
  • eslint
  • babel-eslint
  • eslint-loader
  • eslint-plugin-import
  • eslint-plugin-react
  • eslint-plugin-react-hooks
yarn add eslint babel-eslint eslint-loader eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks -D

5.5 测试

修改 src/index.js

import React from 'react';
import reactDom from 'react-dom';

const App = () => (
  <div>
    test page
  </div>
)
reactDom.render(<App/>, document.getElementById('root'));

重新运行项目, 如果配置正常则会抛出警告

5.6 添加 yarn 脚本, 用于自动修复部分语法不规范的代码
"scripts": {
+   "eslint:fix": "eslint --fix ./src"
  },

通过执行 yarn eslint:fix则会修复项目中部分能够自动修复的不规范代码

六、 引入 Antd 并配置按需加载

这里主要为 .babelrc配置添加插件 babel-plugin-import从而实现 antd 的按需加载

6.1 修改 .babelrc

说明: 配置插件时可以设置实例化名称 import-antd, 这样就可以多次使用同一插件, 如果你还需要使用 babel-plugin-import处理其他组件库

{
+ "plugins": [
+   ["import", {
+     "libraryName": "antd",
+     "libraryDirectory": "es",
+     "style": "css"
+   }, "import-antd"]
+ ],
  "presets": [
    "@babel/preset-react",
    "@babel/preset-env"
  ]
}

6.2 依赖安装
npm i antd -S
npm i babel-plugin-import -D

6,3 测试

src/index中引用样式, 测试是否能够正常使用

import React from 'react';
import reactDom from 'react-dom';
+ import { Button } from 'antd';

const App = () => (
  <div>
+   <Button type="primary">按钮</Button>
  </div>
);
reactDom.render(<App/>, document.getElementById('root'));

七、 版本发布、git commit 规范校验配置

这一节节选我另一篇文章 commit 规范校验配置和版本发布配置, 下面只介绍简单配置方法

7.1 依赖包安装
//husky 包安装
yarn add husky --save-dev

//commitlint 所需包安装
yarn add  @commitlint/config-angular @commitlint/cli --save-dev

//commitizen 包安装
yarn add  commitizen --save-dev
yarn add  commitizen -g

//standard-version 包安装
yarn add  standard-version --save-dev
7.2 配置 commitlint 和 commitizen
//生成 commitlint 配置文件
echo "module.exports = {extends: ['@commitlint/config-angular']};" > commitlint.config.js
//commitizen 初始化
commitizen init cz-conventional-changelog --save-dev --save-exact
7.3 更新 package.json

脚本说明:

  1. release: 自定义要发布的版本, 如: npm run release -- 1.0.0
  2. release💯 执行该脚本, 那么如果当前版本是 1.0.0 那么版本将被提升至 2.0.0
  3. release:010: 执行该脚本, 那么如果当前版本是 1.0.0 那么版本将被提升至 1.1.0
  4. release:001: 执行该脚本, 那么如果当前版本是 1.0.0 那么版本将被提升至 1.0.1
{
  "scripts": {
+   "commit": "git-cz",
+   "release": "standard-version --release-as",
+   "release:100": "npm run release -- major",
+   "release:010": "npm run release -- minor",
+   "release:001": "npm run release -- patch",
  },
+ "husky": {
+   "hooks": {
+     "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
+   }
+ }
}

7.4 commit 方式
  • 全局安装 commitizen 情况下可使用 git cz或者 npm run commit来提交代码
  • 未全局安装 commitizen 情况下可使用 npm run commit来提交代码
7.5 版本发布流程
//1. 切换到指定分支
git checkout master
//2. 更新代码
git pull origin master
//3. 版本发布: 生成 CHANGELOG.md 并创建 tag
npm run release -- --release-as 1.0.0
//4. 更新 tag 至远程分支
git push --follow-tags origin master

八、 更多配置

8.1 webpack 拷贝 public 文件
+ const CopyWebpackPlugin = require('copy-webpack-plugin');

+ const copyWebpackPlugin = new CopyWebpackPlugin(
+   [{ from: path.resolve(__dirname, '../public') }]
+ );

module.exports = {
  plugins: [
+   copyWebpackPlugin,
  ]
};

8.2 定义全局变量
+ const { DefinePlugin } = require('webpack');

+ const definePlugin = new DefinePlugin({
+   _DEV_: false,
+   GLOBAL_SERVICE: {
+     HOST: JSON.stringify('https://www.qianyin925.com:4000'),
+     GRAPHQL_URL: JSON.stringify('/graphql'),
+   },
+ });

module.exports = {
  plugins: [
+   definePlugin,
  ]
};

8.3 自动加载依赖
+ const { ProvidePlugin } = require('webpack');

+ const providePlugin = new ProvidePlugin({
+   _: 'lodash',
+   lodash: 'lodash',
+ });

module.exports = {
  plugins: [
+   providePlugin,
  ]
};

8.4 webpack 定义路径别名
module.exports = {
  resolve: {
+   alias: config.alias || {},
  },
};

8.5 cross-env 设置环境变量

优点: 兼容多个平台

{
  "scripts": {
+   "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
  }
}

8.6 raw-loader 用于加载文本内容(.txt、.md 文件)
module.exports = {
  module: {
    rules: [
      {
        test: /\.(text|md)$/,
        use: 'raw-loader',
      },
    ]
  }
};

MPA

多页面:多入口(entry),多出口(output),多HTML输出(HtmlWebpackPlugin)

module.exports={
  entry: //入口接收string | json
			{app:'index1.js',app2:'index2.js'} 输出要求多输出
  output: {
    path:path.resolve(__dirname,'dist') //指定编译目录
    publicPath:'/', //公共路径 影响资源(图)路径,devserver路径,多页资源路径,开发生产环境基础资源路径,cdn路径
    filename:'js/main.js' 单文件输出 | 'js/[name].js' 多输出  html引入app和app2 配合
  }
  
  plugins:[
    new HtmlWebpackPlugin({关于生成app.html配置}),
    new HtmlWebpackPlugin({关于生成app2.html配置}),
  ]
}

vue-cli4 for MPA

思想

vue的多页面,就是多实例(vue),一个html一个vue实例

创建项目

vue create 目录

项目目录组织

public     //每一个html都来自index.html的拷贝 
	|- index.html			id=index
	|- page1.html			id=page1
	|- pageN.html			...
  |- 无需优化的公共资源
pages
	|- index
		|- index.js 主入口
    |- index.vue 根组件件
  |- page1
		|- page1.js 主入口   对等 index.js入口
    |- page2.vue 根组件件
 	...
components
	|- 通用组件.vue
assets
	|- 通用资源 需要优化
vue.config.js	   配置多页面

配置

module.exports = {
  pages: {
      index: {
          // 应用入口配置,相当于单页面应用的main.js,必需项
          entry: 'src/pages/index/index.js',

          // 应用的模版,相当于单页面应用的public/index.html,可选项,省略时默认与模块名一致
          template: 'public/index.html',

          // npm run build 编译后在dist目录的输出文件名,可选项,省略时默认与模块名一致
          filename: 'index.html',

          // 标题,可选项,一般情况不使用,通常是在路由切换时设置title
          // 需要注意的是使用title属性html文件 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
          title: 'index page config',

          // 包含的模块,可选项
          // chunks: ['index']
      },
      // 只有entry属性时,直接用字符串表示模块入口
      page1: {entry:'src/pages/page1/page1.js',title:'page1 config'},
      page2: {entry:'src/pages/page2/page2.js',title:'page2 config'},
      // page3: 'src/pages/page3/page3.js',
  }
}

create-react-app for MPA

方案1

react-app-rewired

方案2

项目实例

创建

create-react-app 目录

解构配置

yarn eject

配置目录结构

public     //每一个html都来自index.html的拷贝 
	|- index.html			
	|- page1.html			
	|- pageN.html			
  |- 无需优化的公共资源
pages
	|- index
		|- index.js 主入口
    |- index.jsx 根组件件
  |- order
		|- index.jsx 主入口   对等 index.js入口
    |- App.jsx 根组件件
 	...
components
	|- 通用组件.vue
assets
	|- 通用资源 需要优化

config    // eject出来的配置
scripts

配置webpack

在config/webpack.config 配置多入口

//原始
entry:[
   paths.appIndexJs, 
   isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient')
].filter(Boolean),
//修改后的
entry:{
  index: [paths.appIndexJs, isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient')].filter(Boolean),
  query: [paths.appQueryJs, isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient')].filter(Boolean),
  ticket: [paths.appTicketJs, isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient')].filter(Boolean),
  order: [paths.appOrderJs, isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient')].filter(Boolean),
}

多入口文件的路径(paths.appIndexJs)写在paths文件中,到config/paths中添加这几个变量

//原始
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index/index'),
//改后
appHtml: resolveApp('public/index.html'),
appQuery: resolveApp('public/query.html'),
appTicket: resolveApp('public/ticket.html'),
appOrder: resolveApp('public/order.html'),
appIndexJs: resolveModule(resolveApp, 'src/index/index'),
appQueryJs: resolveModule(resolveApp, 'src/query/index'),
appTicketJs: resolveModule(resolveApp, 'src/ticket/index'),
appOrderJs: resolveModule(resolveApp, 'src/order/index'),

多html的产出,在config/webpack.config.js 去配置多个HtmlWebpackPlugin

new HtmlWebpackPlugin(
    Object.assign(
      {},
      {
        inject: true, //允许注入内容到html 在打包输出时
        template: paths.appHtml, //参考模板 指向paths里面的配置
        filename: 'index.html', //输出的html的文件名  
        chunks: ['index'],
      },
      isEnvProduction
        ? {
            minify: {
              removeComments: true,
              collapseWhitespace: true,
              removeRedundantAttributes: true,
              useShortDoctype: true,
              removeEmptyAttributes: true,
              removeStyleLinkTypeAttributes: true,
              keepClosingSlash: true,
              minifyJS: true,
              minifyCSS: true,
              minifyURLs: true,
            },
          }
        : undefined
    )
  ),
new ...,
new ...

可以考虑,把入口和出口,模板html 做一个动态生成,推荐node包(glob)

报错 filter错误时

//config/webpack.config.js

new ManifestPlugin({
  fileName: 'asset-manifest.json',
  publicPath: publicPath,
  generate: (seed, files, entrypoints) => {
    const manifestFiles = files.reduce((manifest, file) => {
      manifest[file.name] = file.path;
      return manifest;
    }, seed);
    const entrypointFiles = entrypoints.main.filter(
      fileName => !fileName.endsWith('.map')
    );
    return {
      files: manifestFiles,
      entrypoints: entrypointFiles, //干掉这一行
    };
  },
})

ManifestPlugin这是针对单一入口的配置,因为单一入口不指定name的情况默认name为main,当改成多入口的方式了之后这里面在entrypoints中自然是读取不到main这个值的,因此就报错,这里将generate这个参数去掉,恢复其默认值即可,或者将entrypoints这个key去掉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值