Skip to content
This repository has been archived by the owner on Aug 30, 2018. It is now read-only.

uedlinker/uedlinker-scripts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

uedlinker-scripts

React 单页应用构建脚本。此脚本使用 Webpack 作为构建工具,使用 Babel 作为编译工具,使用 webpack-server 作为开发服务器,使用 Jest 作为测试工具。

目录

目标

  • 零配置: 此脚本提供默认配置,用户不需要编写任何其他的配置便可以启动项目进行开发。
  • 自定义配置: 在默认配置满足不了开发需求时,用户可以自定义配置
  • 统一维护和升级: 用户不需要专门维护一套自己的配置,每次升级只需要升级 @uedlinker/scripts 包便可。

功能

  • 支持 ES 最新的语法(包括处于草案中的语法)。
  • 支持 JSX 语法。
  • 支持 Flowtype 类型检查。
  • 支持代码分离、动态导入和懒加载。
  • 支持 CSS 自动加前缀。
  • 支持生产环境下压缩代码。
  • 支持热更新(HMR)。
  • 支持离线缓存(PWA)。
  • 提供默认 Polyfills
  • 提供一些便于使用的命令
  • 支持自定义配置

默认支持解析的文件:

  • 脚本:.js.jsx
  • 样式:.css.scss
  • 图片:.bmp.png.jpg.jpeg.gif.svg
  • 字体:.eot.ttf.woffwoff2

还有许多文件不支持解析,但可以在自定义 Webpack 配置中添加文件解析规则。

注意: 此脚本在构建时没有使用 ESLint 检查代码。考虑到前端码农常用的几个编辑器大多都有 ESLint 插件提供实时提示功能,所以没有必要在构建时再次检查。

命令

  • uedlinker-scripts dev 启动开发环境。
  • uedlinker-scripts build 生产环境打包。
  • uedlinker-scripts test 使用 Jest 运行测试代码。
  • uedlinker-scripts analyze 可视化 Webpack 输出文件的大小。

使用

在使用此脚本前,你需要安装 @uedlinker/scripts 包,最好将其作为本地依赖:

npm install --save-dev @uedlinker/scripts

然后在 package.json 中配置命令:

{
  "scripts": {
    "dev": "uedlinker-scripts dev",
    "build": "uedlinker-scripts build",
    "test": "uedlinker-scripts test",
    "test:coverage": "uedlinker-scripts test --coverage",
    "analyze": "uedlinker-scripts analyze"
  }
}

最后,执行命令:

# 启动开发环境
npm run dev

# 生产环境打包
npm run build

# 使用 Jest 运行测试代码
npm run test

# 使用 Jest 运行测试代码并生成覆盖报告
npm run test:coverage

# 可视化 Webpack 输出文件的大小
npm run analyze

目录结构

你必须遵守以下目录约定才能实现此脚本的功能。

your-project-root
├── dist                  // Webpack 构建目标目录,`build` 时自动生成
├── src
│   └── index.js          // 入口文件,必须
├── static                // 静态文件目录,必须
├── babel.config.js       // 自定义 Babel 配置文件
├── package.json
├── server.config.js      // 自定义 webpack-server 配置文件
└── webpack.config.js     // 自定义 Webpack 配置文件

其中 src/index.jsstatic 是必须的。并且,你应该把所有的源文件(需要通过 Webpack 和 Babel 处理的文件)放在 src 目录中,把静态文件(直接复制到目标目录 dist 的文件)放到 static 目录中。

开启 HMR

虽然脚本默认支持 HMR,但也需要编写一些额外的代码。在入口文件中,你需要编写类似下面的代码:

// src/index.js

import React from 'react'
import { render } from 'react-dom'

// 你需要新建一个 `src/App.jsx` 文件,并导出一个可用的 React 组件
import App from './App'

const renderApp = Component => {
  render(
    <Component />,
    document.getElementById('root')
  )
}

renderApp(App)

// 开启 HMR
if (module.hot && process.env.NODE_ENV === 'development') {
  module.hot.accept(['./App'], () => {
    const App = require('./App').default
    renderApp(App)
  })
}

查看详情

开启离线缓存

与开启 HMR 一样,你需要在入口文件中编写下面的代码:

// src/index.js

if (process.env.NODE_ENV === 'production') {
  require('offline-plugin/runtime').install()
}

查看详情

导入图片和字体文件

在导入图片和字体文件时,在文件大小不超过 8kb 时,使用 url-loader 内联到 JS 代码中,超过 8kb 时,使用 file-loader 复制此文件到目标目录 dist 中。但你也可以通过导入选项选择导入方式:

// 强制使用 url-loader 内联到 JS 代码中,注意后面的 `?inline` 选项
import myImg1 from './assets/images/example1.png?inline'

// 强制使用 file-loader 复制文件到 `dist` 目录中,注意后面的 `?external` 选项
import myImg2 from './assets/images/example2.png?external'

测试

此脚本集成了 Enzyme 测试工具,并配置好了适配器,所以你可以直接在测试代码中使用 Enzyme 的功能。

你也可以在 scripts 命令中使用 Jest 的命令行参数。例如生成测试覆盖报告:

{
  "scripts": {
    "test:coverage": "uedlinker-scripts test --coverage"
  }
}

在大多数情况下,建议通过配置文件自定义 Jest 配置

自定义配置

自定义环境变量

此脚本默认提供了 NODE_ENVBABEL_ENV 两个环境命令,它们是只读的,不能够通过命令行修改这两个环境变量的值,只能在前端代码中读取到这两个变量,因为这两个变量分别决定了 Webpack 和 Babel 的运行模式,用户修改会导致它们的运行模式发生不可预测的变化。在执行不同命令时,它们的值也不一样,在 uedlinker-scripts dev 命令中,它们的值都是 development,在 uedlinker-scripts build 命令中,它们的值都是 production

你可以在你的命令中自定义环境变量:cross-env UEDLINKER_MY_ENV=awesome uedlinker-scripts dev。其中使用了 cross-env 这个工具,它的作用是跨平台定义环境变量。这样,你可以在你的前端代码中通过 process.env.UEDLINKER_MY_ENV 获取到值 awesome

// package.json
{
  "scripts": {
    "dev": "cross-env UEDLINKER_MY_ENV=awesome uedlinker-scripts dev"
  }
}
// src/index.js
const myEnv = process.env.UEDLINKER_MY_ENV
console.log(myEnv) // => 'awesome'

注意:所有自定义环境变量都必须以 UEDLINKER_ 开头。 因为在 process.env 上还挂载了很多其他的环境变量,这样做防止用户在自定义时不小心修改了其他的环境变量的值。

自定义 Webpack 配置

在你的项目根目录下添加一个 webpack.config.js 文件就能够自定义 Webpack 配置。你可以导出一个对象或一个函数。当导出对象时,此脚本会合并你的自定义配置;当导出函数时,此脚本会把默认配置注入到你的函数中,并执行一次这个函数,使用函数返回的对象作为 Webpack 的配置。下面我们以添加一个解析 .less 的配置为例来说明:

// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const env = process.env.NODE_ENV
const isProd = env === 'production'

module.exports = defaultConfig => {
  defaultConfig.module.rules.push({
    test: /\.less$/,
    use: [
      isProd ? MiniCssExtractPlugin.loader : 'style-loader',
      'css-loader',
      'less-loader'
    ],
  })
  return defaultConfig
}

在此脚本中,默认使用 mini-css-extract-plugin 作为提取 CSS 的工具。在这些依赖包中,你不需要再安装 mini-css-extract-pluginstyle-loadercss-loader 包,因为脚本已经默认安装,并且你自定义配置中的 MiniCssExtractPlugin.loader 必须是和脚本中使用的 MiniCssExtractPlugin.loader 一模一样(必须是同一个包),否则会出错。

在你自定义 Webpack 配置前,请先查看 Webpack 官方文档和此脚本中的开发环境配置生产环境配置

自定义 webpack-server 配置

在你的项目根目录下添加一个 server.config.js 文件就能够自定义 webpack-server 配置。与自定义 Webpack 配置一样,你可以导出一个对象或一个函数。当导出对象时,此脚本会合并你的自定义配置;当导出函数时,此脚本会把默认配置注入到你的函数中,并执行一次这个函数,使用函数返回的对象作为 webpack-server 的配置。下面我们以开启热更新信息提示功能为例说明(默认遇到警告或错误时才提示):

// server.config.js
module.exports = {
  hotClient: {
    logLevel: 'info',
  },
}

在你自定义 webpack-server 配置前,请先查看 webpack-server 的配置文档和脚本中的默认 webpack-server 配置

自定义 Babel 配置

在你的项目根目录下添加一个 babel.config.js 文件就能够自定义 Babel 配置。与自定义 Webpack 配置一样,你可以导出一个对象或一个函数。当导出对象时,此脚本会合并你的自定义配置;当导出函数时,此脚本会把默认配置注入到你的函数中,并执行一次这个函数,使用函数返回的对象作为 Babel 的配置。

在你自定义 Babel 配置前,请先查看 Babel 的配置文档和脚本中的默认 Babel 配置

自定义 Jest 配置

在你的项目根目录下添加一个 jest.config.js 文件就能够自定义 Jest 配置。与自定义 Webpack 配置一样,你可以导出一个对象或一个函数。当导出对象时,此脚本会合并你的自定义配置;当导出函数时,此脚本会把默认配置注入到你的函数中,并执行一次这个函数,使用函数返回的对象作为 Jest 的配置。

在你自定义 Jest 配置前,请先查看 Jest 的配置文档和脚本中的默认 Jest 配置

选项

在自定义配置的基础上,提供了便捷选项。在你的项目根目录下添加 uedlinker.config.js 文件,然后导出一个对象便可。

字段 类型 含义 默认值 环境
templatePath string HTML 模板路径 默认模板 开发环境和生产环境
polyfillsPath string Polyfills 路径 默认 Polyfills 开发环境和生产环境
publicPath string 公共资源路径,一般情况下为 CDN 地址 '/' 生产环境
sourceMap boolean 是否开启 Souce Map false 生产环境
removeConsole boolean 移除 console.* true 生产环境

示例:

// uedlinker.config.js
module.exports = {
  templatePath: './src/index.html',        // 路径相对于路项目根目录
  polyfillsPath: './src/libs/polyfills.js',  // 路径相对于路项目根目录
  publicPath: '//cdn.example.com',         // 公共资源的 CDN 地址
  sourceMap: true,                         // 开启 Souce Map
  removeConsole: false,                    // 关闭移除 console.* 功能
}

问题

当你遇到问题时,可以在这里提出你的问题,我会尽量解决。如果你能够提供解决方案或 PR,那就最好不过了。