H5入门01-React+dva+webpack搭建项目框架

2019-02-26  本文已影响26人  最爱的火

H5入门01-dva+webpack搭建框架

对于移动端开发者而言,开发H5一般使用 React +Dvajs + Webpack+andt.mobile进行开发,下面就用它们来搭建项目。

基础框架搭建

dva框架用于路由、架构、异步操作和网络请求。使用dva new创建项目时,默认使用roadhog进行打包和开启服务。

webpack用于打包,使用webpack-dev-server来开启服务。相比roadhog,更加稳定,但是配置更加复杂。如果使用roadhog打包,就不需要安装webpack。

andt.mobile是阿里的ui框架,封装了很多常用的ui组件,功能强大,但是使用有点复杂。

注意:需要先安装npm和python。

参考文章:http://www.cnblogs.com/axel10/p/8973783.html

1 安装dva框架

截止 2017.1,最流行的社区 React 应用架构方案如下。

缺点:要引入多个库,项目结构复杂。

dva = React-Router + Redux + Redux-saga, 是对上面三个 React 工具库的封装,还额外内置了 fetch,简化了 API,让开发 React 应用更加方便和快捷。

安装 dva-cli

通过 npm 安装 dva-cli 并确保版本是 0.9.1 或以上。

$ npm install dva-cli -g
$ dva -v
dva-cli version 0.9.1

创建新应用

安装完 dva-cli 之后,就可以在命令行里访问到 dva 命令。现在,你可以通过 dva new 创建新应用。

$ dva new dva-quickstart

这会创建 dva-quickstart 目录,包含项目初始化目录和文件,并提供开发服务器、构建脚本、数据 mock 服务、代理服务器等功能。

然后我们 cd 进入 dva-quickstart 目录,并启动开发服务器:

$ cd dva-quickstart
$ npm start

几秒钟后,你会看到以下输出:

Compiled successfully!

The app is running at:

  http://localhost:8000/

Note that the development build is not optimized.
To create a production build, use npm run build.

在浏览器里打开 http://localhost:8000 ,你会看到 dva 的欢迎界面。

2 安装webpack

如果使用默认的roadhog打包,就跳过此步骤。

如果是webpack打包,就可以先删除roadhog的配置,再安装webpack。

基本配置

安装框架

//安装webpack框架
npm install --save-dev webpack webpack-cli 
//安装webpack服务器,用于本地调试
npm install --save-dev webpack-dev-server
//安装本地打包框架
npm install --save-dev lodash 
//安装css样式加载框架
npm install --save-dev style-loader css-loader
//安装scss样式加载框架
npm install --save-dev node-sass sass-loader
//安装文件加载框架
npm install --save-dev file-loader
//安装html处理框架
npm install --save-dev html-webpack-plugin
//安装文件清理框架
npm install --save-dev clean-webpack-plugin 
//安装样式分离框架,用于将样式文件单独打包,提高加载速度。注意直接安装extract-text-webpack-plugin会发生兼容性问题。
npm install --save-dev extract-text-webpack-plugin@next
//安装webpack合并框架,用来合并webpack的配置文件
npm install --save-dev webpack-merge
//用来拷贝文件
npm install --save-dev copy-webpack-plugin
//用来压缩文件
npm install --save-dev uglifyjs-webpack-plugin

webpack.base.config.js

const path = require('path');
const webpack = require('webpack');

//配置参数
var config = {
  //入口文件
  entry: './src/index.js',
  //出口文件
  output: {
    //name是入口文件名,默认为main,当存在多个入口文件是需要使用
    filename: 'main.js',
    //__dirname为系统变量,代表当前目录名
    path: path.resolve(__dirname, 'dist'),
    //指定所有资源的基础路径,默认为空,一般不需要指定
    publicPath: '',
  },
  //用来追踪源代码,因为webpack打包源代码时,可能会很难追踪到错误和警告在源代码中的原始位置
  devtool: 'inline-source-map',
  //配置webpack服务器的参数
  devServer: {
    //热替换,当本地文件更新后,浏览器页面自动刷新
    hot: true,
    //设置代理
    proxy: {
      //对以'/open/api/weather/'开头的请求进行代理
      '/open/api/weather/*': {
        //需要代理的地址
        target: 'https://www.sojson.com',
        // 允许https请求
        secure: true,
        //允许跨域
        changeOrigin: true
      }
    }
  },
  //加载模块
  module: {
    //加载规则
    rules: [
      {
        //加载js文件
        test: /\.jsx?$/,
        //指定加载器
        use: ['babel-loader'],
        //指定需要加载的目录
        include: path.join(process.cwd(), 'src')
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: ['file-loader?limit=8192&name=image/[name].[hash:4].[ext]'],
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: ['file-loader?limit=8192&name=image/[name].[hash:4].[ext]']
      }
    ]
  },
  plugins: [
    //热替换插件
    new webpack.HotModuleReplacementPlugin(),
    //定义全局变量,webpack编译后生效。_ENV_:将_ENV_定为全局变量,开发时会有警告。'window._ENV_':在window对象中定义_ENV_属性,开发时没警告。
    new webpack.DefinePlugin({_ENV_: JSON.stringify({isMock: false}), 'window._ENV_': JSON.stringify({isMock: false})}),
  ]
}

module.exports = config;

package.json

{
    ...
    "scripts": {
     "start": "webpack-dev-server --hot --open --port 1111 --config  webpack.dev.config.js",
     "build": "webpack --config webpack.dev.config.js",
    },
    ...
}

注意:如果使用roadhog打包,会自动识别webpack.config.js文件,并且要求webpack.config.js返回一个函数。

支持非ES5语法

安装框架:

//安装babel转码器
npm install --save-dev @babel/core
//用来转换ES6中新的API。babel默认只转换新的JS语法,比如Symbol、Promise等全局对象不会转码
npm install --save @babel/polyfill
//安装babel转码器的加载器
npm install --save-dev babel-loader
//用来支持react框架
npm install --save-dev @babel/preset-react
//用来支持ES6语法
npm install --save-dev @babel/preset-es2015
//用来支持最新的ES语法
npm install --save-dev @babel/preset-env
//用来支持已经正式提案,但是还没正式发版的ES语法。已废弃。
npm install --save-dev @babel/preset-stage-1
//用来支持Decorators语法。修饰器(Decorator)是ES7提案中的一个函数,用来修改类的行为。
npm install --save-dev @babel/plugin-proposal-decorators
//用来支持babel-runtime语法。@babel/runtime用于避免重复编译文件。
npm install --save-dev @babel/plugin-transform-runtime
//用于按需加载第三方库中的组件,而不是加载整个库
npm install --save-dev babel-plugin-import
//用于异步加载文件。在运行时加载,而不是编译时加载
npm install --save-dev @babel/plugin-syntax-dynamic-import
//用于在class中声明属性
cnpm install --save-dev babel-plugin-transform-class-properties

注意:babel7.0之前,使用babe-命名,7.0以后,使用@babel/命名。

.babelrc

{
  //预设转码,用来将非ES6语法转换为ES6语法
  "presets": [
    "react",
    "env",
    "stage-1"
  ],
  "plugins": ["transform-decorators-legacy" ,"transform-runtime"]
}

babel/polyfill的使用:

开发配置

webpack.dev.config.js

const baseWebpackConfig = require('./webpack.base.config.js');
const merge = require('webpack-merge');

//开发环境配置参数
var config = {
  //加载模式:开发模式或生产模式
  mode: "development",
  //加载模块
  module: {
    //加载规则
    rules: [
      {
        test: /\.s?css$/,
        //将样式文件打包到js中
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
    ]
  },
};

module.exports = merge(baseWebpackConfig, config);

webpack把js文件打包,需要一个入口页来加载:index.html,默认位于项目的根目录。

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>CommonH5</title>
</head>
<body>
<div id="root"></div>
<!--导入打包后生成的js文件,注意引用路径要与webpack.config.js中配置的出口文件保持一致-->
<script src="main.js">
</script>
</body>
</html>

生产配置

webpack.prod.config.js

const baseWebpackConfig = require('./webpack.base.config.js');
const merge = require('webpack-merge');
const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

//生产环境配置文件
var config = {
  //指定生产环境
  mode: "production",
  //加载模块
  module: {
    //加载规则
    rules: [
      {
        test: /\.s?css$/,
        //将样式文件与js分离,提高加载速度
        use: ExtractTextPlugin.extract({fallback: 'style-loader', use: ['css-loader', 'sass-loader']})
      },
    ]
  },
  plugins: [
    //压缩插件
    new UglifyJsPlugin({
      uglifyOptions: {
        compress: {
          warnings: false
        }
      },
      parallel: true
    }),
    //html加载插件
    new HtmlWebpackPlugin({
      filename: path.join(process.cwd(), 'dist/index.html'),
      template: 'index-build.html',
      inject: true,
      hash: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      chunksSortMode: 'dependency'
    }),
    //分离样式插件
    new ExtractTextPlugin({filename: 'main.css'}),
    // keep module.id stable when vendor modules does not change
    new webpack.HashedModuleIdsPlugin(),
    //用来复制文件
    new CopyWebpackPlugin([]),
  ]
}

module.exports = merge(baseWebpackConfig, config);

生产打包时,需要在dist目录生成一个index.html文件,生成这个文件需要配置一个模板文件:index-duild.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>CommonH5</title>
</head>
<body>
<div id="root"></div>
</body>
</html>

图片引用

使用webpack打包时,图片不能直接传路径。

//这样webpack打包时,会解析成http://localhost:1111/assets/yay.jpg,从而获取失败
<img src='../assets/yay.jpg'/>

有两种方式:

1.使用url函数:只能在.scss中使用

.float1 {
    background: url(../../assets/yay.jpg) no-repeat center 0;
}

2.使用requrie函数:在.scss和.js中都能使用

<img src={require('../assets/yay.jpg')}/>

3 安装antd-mobile

通过 npm 安装 antd-mobilebabel-plugin-importbabel-plugin-import 是用来按需加载 antd 的脚本和样式的。

npm install --save antd-mobile
npm install --save-dev babel-plugin-import

如果使用roadhog打包,编辑 .webpackrc,使 babel-plugin-import 插件生效。

{
  "extraBabelPlugins": [
    ["import", { "libraryName": "antd-mobile", "libraryDirectory": "es", "style": "css" }]
  ]
}

如果使用webpack打包,编辑 .babelrc,使 babel-plugin-import 插件生效。并且打包css文件时,不要排除node_modules,否则antd-mobile的css无法生效。

{
  ...
  "plugins": [
    ["import", { "libraryName": "antd-mobile", "libraryDirectory": "es", "style": "css" }],
    ...
  ]
}

4 调试与打包

调试:npm start

打包:npm build。

打包后,会在dist目录生成所有的文件,包含一个index.html、一个main.css、n个图片等资源、n个js文件。

注意:使用dva构建项目默认生成的IndexPage.js,引用样式的方式在webpack中不支持,应改为:

import './IndexPage.scss';
...
<div className={'normal'}>

第一个页面

1 简单页面

页面统一在src/routes目录进行开发,一个页面由一个js文件和一个scss(或css)文件组成。

首先写js文件。

Demo.js

import React from 'react';
import {connect} from 'dva'
import {queryDemoData} from '../services/serverDemo'
import {routerRedux} from 'dva/router';
import './Demo.scss'

//基础样式名
const baseStyle = 'demo';
//数据源
var dataSource = null;

/**
 * Demo页面
 */
@connect(() => ({}))
export default class Demo extends React.Component {

  //构造函数
  constructor(props) {
    super(props);
    //使用state保存dataSource
    this.state = {
      dataSource: dataSource,
    }
  }

  //界面渲染之前的回调函数
  componentWillMount() {
    // this.getTestData();
    this.getRealData();
  }

  //界面渲染函数
  render() {
    let list = this.renderList();
    return (
      <div className={`${baseStyle}`}>
        {list}
        <button className={`${baseStyle}-button`} onClick={()=>this.onGo()}>页面跳转</button>
      </div>
    )
  }

  /**
   * 获取测试数据
   */
  getTestData() {
    dataSource = [
      {
        img: 'https://zos.alipayobjects.com/rmsportal/dKbkpPXKfvZzWCM.png',
        text: '6217000011112666'
      },
      {
        img: 'https://zos.alipayobjects.com/rmsportal/XmwCzSeJiqpkuMB.png',
        text: '6217000011112777'
      }
    ];
    this.setState({dataSource: dataSource});
  }

  /**
   * 获取真实数据
   */
  getRealData() {
    queryDemoData().then((result)=> {
      console.log(result);
      //如果请求成功,就刷新页面
      if (result.data.code == "000000") {
        dataSource = result.data.data.list;
      } else {
        dataSource == null;
      }
      this.setState({dataSource: dataSource});
    }, (error)=> {
      console.log(error);
    });
  }

  /**
   * 生成列表
   */
  renderList() {
    let data = this.state.dataSource;
    if (!data || !data.length) {
      return null;
    }

    let items = [];
    for (let i = 0; i < data.length; i++) {
      let itemData = data[i];
      let key = `ListItem${i}`;
      let item =
        <li key={key} className={`${baseStyle}-list-row`}>
          <div className={`${baseStyle}-list-row-content`}>
            <img src={`${itemData.img}`} className={`${baseStyle}-list-row-img`}/>
            <span className={`${baseStyle}-list-row-text`}>{itemData.text}</span>
          </div>
          <div className={`${baseStyle}-list-separator`}/>
        </li>;
      items.push(item);
    }

    return (
      <ul className={`${baseStyle}-list`}>
        {items}
      </ul>
    );
  }

  /**
   * 页面跳转
   */
  onGo() {
    //指定需要跳转的页面,页面路径为router.js中配置的path
    let action = routerRedux.push('/');
    //添加@connect后,redux会给页面添加dispatch属性,通过dispatch来分发action
    this.props.dispatch(action);
  }
}

注意:如果React.Component写成React.componentReact.createComponent,则需要添加constructor(props) {super(props);},否则webpack打包后会报错。

然后,写样式文件。创建样式时,统一以文件名作为所有样式的开头(通过&连接),这样可以避免样式被覆盖。

Demo.scss

.demo {
  width: 100%;
  height: 100%;
  background-color: #F5F5F5;
  overflow: auto;

  //代表.css-demo-list.使用&连接上层样式名
  &-list {
    //布局方式
    display: flex;
    //flex方向.row代表水平排列,column代表垂直排列
    flex-direction: column;
    width: 100%;
    height: 100%;
    padding: 0px;
    margin: 0px;

    &-row {
      display: flex;
      flex-direction: column;
      width: 100%;
      height: 60px;

      &-content {
        display: flex;
        flex-direction: row;
        //flex方向的对齐
        justify-content: flex-start;
        //非flex方向的对齐:如果flex是水平的,那么内容垂直居中;如果flex是垂直的,那么内容水平居中;
        align-items: center;
        width: 100%;
        height: 100%;
      }

      &-img {
        width: 40px;
        height: 40px;
        margin-left: 10px;
      }

      &-text {
        width: 100%;
        margin-left: 10px;
        font-size: 20px;
      }
    }
    //分割线样式
    &-separator {
      width: 100%;
      height: 1px;
      background-color: #E5E5E5;
    }
  }
  &-button {
    width: 100%;
    height: 60px;
    margin: 10px;
    font-size: 20px;
    color: #00aaee;
    background: #FFFFFF;
    border: 1px solid #00aaee;
    border-radius: 4px;
  }
}

注意:css中属性名没有驼峰式,使用-分开,比如:在style中的borderTop在css中要写成border-top

最后,配置路由。页面完成后,需要在src/router.js中配置路由

import React from 'react';
import {Router, Route, Switch} from 'dva/router';
import IndexPage from './routes/IndexPage';
import Demo from './routes/Demo';

function RouterConfig({history}) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={IndexPage}/>
        <Route path="/demo" exact component={Demo}/>
      </Switch>
    </Router>
  );
}

export default RouterConfig;

然后打开http://localhost:1111/#/demo,就可以访问页面了。

2 请求本地数据

dva构建项目时,帮我们封装了网路请求,可以方便的请求本地json数据和网络数据。

首先,创建本地数据。在mock目录下,创建json文件作为本地数据。

queryDemoData.json

{
  "code": "000000",
  "msg": "成功",
  "data": {
    "list": [
      {
        "img": "https://zos.alipayobjects.com/rmsportal/dKbkpPXKfvZzWCM.png",
        "text": "6217000011112666"
      },
      {
        "img": "https://zos.alipayobjects.com/rmsportal/XmwCzSeJiqpkuMB.png",
        "text": "6217000011112777"
      }
    ]
  }
}

然后,创建请求方法。在src/services下创建请求方法。

demo.js

import request from '../utils/request';

export function queryDemoData() {
  //获取本地数据
  return request('/mock/queryDemoData.json');
}

然后,在页面调用请求方法。

//界面渲染之前的回调函数
componentWillMount() {
  this.getRealData();
}

/**
 * 获取真实数据
 */
getRealData() {
  queryDemoData().then((result)=> {
    console.log(result);
    //如果请求成功,就刷新页面
    if (result.data.code == "000000") {
      dataSource = result.data.data.list;
    } else {
      dataSource == null;
    }
    this.setState({dataSource: dataSource});
  }, (error)=> {
    console.log(error);
  });
}

3 请求网络数据

首先,设置代理。修改webpack.base.config.js的配置,在devServer中设置代理。

devServer: {
  //热替换,当本地文件更新后,浏览器页面自动刷新
  hot: true,
  //设置代理
  proxy: {
    //对以'/open/api/weather/'开头的请求进行代理
    '/open/api/weather/*': {
      //需要代理的地址
      target: 'https://www.sojson.com',
      // 允许https请求
      secure: true,
      //允许跨域
      changeOrigin: true
    }
  }
},

设置代理时,需要注意以下规则:

然后,创建请求方法。在src/services下创建请求方法。

import request from '../utils/request';

export function queryDemoData() {
  //_ENV_是通过webpack.DefinePlugin定义的系统变量,dev代表开发环境,prod代表生产环境.
  if (_ENV_ == 'dev') {
    //获取本地数据
    return request('/mock/queryDemoData.json');
  } else {
    //获取网路数据.需要先在devServer中设置代理.
    return request('/open/api/weather/json.shtml?city=北京');
  }
}

然后,调用请求方法。同上。

4 页面跳转

首先,添加配置。

import {connect} from 'dva';
//用于生成页面跳转的action
import {routerRedux} from 'dva/router';

//添加@connect,参数可为空。用于给页面添加dispatch属性,
@connect()
export default class Demo extends React.Component 

注意:connect还可以这样使用:export default connect()(IndexPage);

然后,跳转页面

/**
 * 页面跳转
 */
onGo() {
  //指定需要跳转的页面,页面路径为router.js中配置的path
  let action = routerRedux.push('/');
  //添加@connect后,redux会给页面添加dispatch属性,通过dispatch来分发action
  this.props.dispatch(action);
}

5 数据传递

首先,创建model。model用来保存应用的数据,统一在src/models目录下配置。

modelDemo.js

export default {
  //model的名字,同时也是他在全局state(应用数据,由多个model组成)上的属性
  namespace: 'demo',
  //当前model的初始值.页面之间是通过model来传递数据的
  state: {demoData: '这是测试Demo',},
  //创建同步修改器,根据action(指令)同步修改当前model的数据,返回修改后的数据
  reducers: {
    /**
     * 同步修改器需要两个参数state和action,state代表当前modal的数据,action指定如何修改当前modal的数据
     * action包含两个属性type和payload
     * type为[model名]/[修改器名],比如:'demo/save'
     * payload为对象,是action传递的数据
     */
    save(state, action) {
      return {...state, ...action.payload};
    },
  },
  //创建异步修改器,根据action(指令)异步修改当前model的数据,返回修改后的数据
  effects: {
    /**
     * 异步修改器使用Generator函数,需要两个参数action和effects,action与同步修改器的action一样,effects定义异步操作
     * effects包含以下属性:
     * call:用于调用异步逻辑,支持promise
     * put:用来发送action(指令),参数为action
     * select:参数为函数(state) => state.demo.demoData,用于从全局state中获取数据
     */
      *fetch({payload}, {call, put, select}) {
      yield call();
      yield put({type: 'save'});
      var data = yield select(state => state.demo.demoData);
    },
  },
};

然后,应用model。在src/index.js中添加model。

app.model(require('./models/modelDemo').default);

然后,发送数据。

onGo() {
    //使用dispacth(action)修改model的数据
    this.props.dispatch({
      //指定model和修改器,格式为[namespace]+[函数名]
      type: 'demo/save',
      //传给修改器的数据
      payload: {
        demoData: '修改后的数据',
      }
    });

  //指定需要跳转的页面,页面路径为router.js中配置的path
  let action = routerRedux.push('/');
  //添加@connect后,redux会给页面添加dispatch属性,通过dispatch来分发action
  this.props.dispatch(action);
}

然后,接收数据。比如:在IndexPage.js中通过connect接收model中保存的数据。

/**
 * 使用@connect(),并且传递一个函数为参数时,代表接收model中保存的数据
 * 函数的参数state代表全局state,全局state保存了所有的model数据.
 * 函数的返回值会被保存到当前页面的props中,通过this.props.来获取
 */
@connect((state) => ({demoData: state.demo.demoData}))
export default class IndexPage extends React.Component {

  componentWillMount() {
    //打印接收的model数据
    console.log(this.props.demoData);
  }
}  

调试

1 添加断点

方法一:

在代码中,添加代码debugger;,即在此处添加断点;

方法二:

在浏览器调试界面,选择Sources-top-webpack-internal://-.-src目录下,找到对应的js文件,然后在js页面左侧,左键点击提交断点。

2 react-devtools调试

react-devtools相比chrome的调试工具,功能更强大。通过在浏览器中安装这个插件,可以查看组件的层次、各个组件的Props、States等信息。

下载地址:https://www.crx4chrome.com/down/62541/crx/

安装步骤:先下载.crx文件,然后打开更多工具-扩展程序,然后将.crx文件拖进去

3 Android调试

首先,在android上安装Stetho:https://reactnative.cn/docs/debugging/

然后,在谷歌浏览器上打开chrome://inspect

注意:打开调试页面后,可以在地址输入栏打开自己的H5页面,这样就可以在自己的H5页面上调试Native的功能。

常见问题

1 npm查看模块版本

查看服务器上的模块版本:

  1. 查看所有的版本信息:npm view [moduleName] versions
  2. 查看最新的版本信息:npm view [moduleName] version
  3. 查看完整的版本信息:npm info [moduleName]

查看本地的模块版本:

  1. 查看本地安装的版本:npm ls [moduleName]。注意,需要在模块的安装目录执行命令,比如:package.json所在的目录。
  2. 查看全局安装的版本:npm ls [moduleName] -g

2 npm安装模块

2.1 指定版本安装模块:

方法一:

  1. package.json的dependencies中声明模块名和版本号,比如:"redux": "^4.0.0"
  2. package.json所在的目录下,运行命令:npm install

方法二:

使用@[版本号],比如:npm i --save redux@4.0.0;

2.2 自动安装合适版本的模块:

package.json所在的目录下,运行命令:npm install --save [moduleName]

如果要安装到开发环境,运行命令:npm install --save-dev [moduleName]

2.3 ~和^的作用和区别:

2.4 npm WARN处理

安装模块时,可能因为缺少依赖组件导致部分组件安装失败,比如:

npm WARN eslint-plugin-react-native@3.2.1 requires a peer of eslint@^3.17.0 || ^4.0.0 but none was installed.

解决办法:

安装缺少的依赖组件,比如:npm install --save eslint

3 node-sass安装失败

出现Cannot download https://github.com/sass/node-sass/releases/download/版本号/XXX_binding.nod情况,是因为node-sass被墙了。

3.1 使用淘宝镜像源(推荐)

设置变量 sass_binary_site,指向淘宝镜像地址。示例:

npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/

// 也可以设置系统环境变量的方式。示例
// linux、mac 下
SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/ npm install node-sass

// window 下
set SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/ && npm install node-sass

或者设置全局镜像源:

npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/

3.2 使用cnpm安装

npm install -g cnpm --registry=https://registry.npm.taobao.org

cnpm i --save-dev node-sass

最后

代码:https://gitee.com/yanhuo2008/CommonH5

上一篇下一篇

猜你喜欢

热点阅读