webpack、sass、react、redux的简易demo入门

最开始只是想综合的初略学习下这几种技术,所以萌生了搭建一个简单的结构的想法;整个结构应该没有什么问题;已经放到了github上,地址:webpack、sass、react、redux的简易demo入门

webpack

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

我自己对webpack的使用也不是很熟练,还没有很明白webpack的设计思维,所以在配置的时候也是一脸懵逼,跟着官方文档和一些社区的文章来一步一步配置,主要还是需要知道这几个配置:

  • 入口(entry)
  • 输出(output)
  • loader
  • 插件(plugins)
  • 解析(Resolve)

入口(entry)

起点或是应用程序的起点入口。从这个起点开始,应用程序启动执行。如果传递一个数组,那么数组的每一项都会执行。

entry字段可以是string | [string] | object { <key>: string | [string] }或者是函数【函数返回值是上面的三种类型中的一种】,本次demo的选择是对象来处理,如下:

entry: {
        home: './src/scripts/pages/home/index.js'
        // homecss: './src/styles/pages/home.scss'  // scss入口放到最开始的js中,webpack无法处理非js文件
    },

输出(output)

output 位于对象最顶级键(key),包括了一组选项,指示 webpack 如何去输出、以及在哪里输出你的「bundle、asset 和其他你所打包或使用 webpack 载入的任何内容」。

通常而言,通过 output.filename 和 output.path 属性,来告诉 webpack bundle 的名称,以及我们想要生成(emit)到哪里。demo中的配置如:

output: {
        path: path.join(__dirname + '/src/dist'),// publicPath:'/'
        // publicPath: path.join(__dirname + '/src/dist/'),// 加载外部资源,此选项指定在浏览器中所引用的「此输出目录对应的公开 URL」
        filename: 'js/[name].js'
    }

需要注意的是,filename: 'js/[name].js'这么写是因为webpack支持入口文件为多个文件时可以配置不同的输出文件名,参考output-filename

loader

loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图可以直接引用的模块。

重要的是要记得,在 webpack 配置中定义 loader 时,要定义在 module.rules 中,而不是 rules。

module: {
        rules: [
            {
                test: /\.js$/,exclude: /(node_modules|bower_components)/,use: {
                    loader: 'babel-loader',options: {
                        presets: ['@babel/preset-env','@babel/stage-3','@babel/react']
                    }
                }
            },{
                test: /\.scss$/,use: extractSass.extract({
                    use: [{
                        loader: "css-loader"
                    },{
                        loader: "sass-loader"
                    }],// publicPath: './../',// 加载外部资源,把路径重新定义到dist目录下,而不是css里面
                    // use style-loader in development
                    fallback: "style-loader"
                })
            },{
                test: /\.(png|svg|jpg|gif|jpeg)$/,use: [
                    {   
                        loader: 'file-loader',options: {
                            name: '[name].[ext]',useRelativePath: true,// 图片相对路径
                            outputPath: 'images/'
                        }
                    }
                ]
            }
            ]
    }

以上是demo的配置,在 webpack 的配置中 loader 有两个目标。

  1. 识别出应该被对应的 loader 进行转换的那些文件。(使用 test 属性)
  2. 转换这些文件,从而使其能够被添加到依赖图中(并且最终添加到 bundle 中)(use 属性)

可以看到,同一个文件可以顺序使用多个loader来加载,每个loader可以传递参数来进行特殊处理。

插件(plugins)

插件是 wepback 的支柱功能。webpack 自身也是构建于,你在 webpack 配置中用到的相同的插件系统之上!插件目的在于解决 loader 无法实现的其他事。
webpack 插件是一个具有 apply 属性的 JavaScript 对象。apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问。

由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例。根据你的 webpack 用法,这里有多种方式使用插件。插件使用插件列表

demo中使用了两个pluginsextract-text-webpack-plugin & DefinePlugin,都是按照官方插件文档配置的。

解析(Resolve)

这些选项能设置模块如何被解析。webpack 提供合理的默认值,但是还是可能会修改一些解析的细节。关于 resolver 具体如何工作的更多解释说明,请查看模块解析方式。

简单的说,就是会帮我们弄好一些默认的选项,比如别名aliasextensions模块默认后缀、mainFiles默认文件入口等;

resolve: {
        mainFiles: ["index"],extensions: ['.js','.jsx'],alias: {
            'stylepages': path.join(__dirname + '/src/styles/pages'),'scripts': path.join(__dirname + '/src/scripts/pages'),'commonjs': path.join(__dirname + '/src/scripts/common')
        }
    }

遇到问题

关于webpack无法把css文件作为入口,需要在js中引入css,然后进行css的分离

关于sass使用@import时来使用alias别名配置的路径时不被正确解析,sass-loader需要在使用别名的前面加上~,stylelib是别名,使用时@import '~stylelib/base.scss';

关于sass和图片等外部资源的打包出现的路径不一致,,有以下几种方法:

  • 第一种方法,可以在配置fileloader的时候使用相对路径:useRelativePath
{
    test: /\.(png|svg|jpg|gif|jpeg)$/,use: [
           {   
              loader: 'file-loader',options: {
                   name: '[name].[ext]',// 图片相对路径
                   outputPath: 'images/'
                 }
              }
          ]
}
  • 第二种方法,在使用ExtractTextWebpackPlugin的时候,可以根据已有的loader来重新提取loader,在提取新的loader时,可以配置公共路径publicPath
const ExtractTextPlugin = require("extract-text-webpack-plugin");

const extractSass = new ExtractTextPlugin({
    filename: "css/[name].css",disable: process.env.NODE_ENV === "development"
});


// loader 里面
{
   test: /\.scss$/,use: extractSass.extract({
         use: [{
                loader: "css-loader"
              },{
                 loader: "sass-loader"
              }],publicPath: './../',// 把路径重新定义到dist目录下,而不是css里面
       // use style-loader in development
       fallback: "style-loader"
    })
}
  • 第三种方法,直接在所有的输出目录处使用当前的打包路径,publicPath
output: {
     path: path.join(__dirname + '/src/dist'),publicPath:'./'
     // publicPath: path.join(__dirname + '/src/dist/'),// 加载外部资源,此选项指定在浏览器中所引用的「此输出目录对应的公开 URL」
     filename: 'js/[name].js'
    }

sass

Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能,这些拓展令 CSS 更加强大与优雅。使用 Sass 以及 Sass 的样式库(如 Compass)有助于更好地组织管理样式文件,以及更高效地开发项目。

使用sass可以感受到以下几点的优势:

  1. 合理的嵌套规则,不需要重复书写selector。
  2. 变量$、占位符%都可以很好的提供复用性
  3. 函数、运算可以很好的增加灵活性

这里就不多说sass的学习了,可以查看sass中文sass官网

react

React 是一个采用声明式,高效而且灵活的用来构建用户界面的框架。
学习react的重要内容包括:
  1. jsx的书写语法
  2. 组件Components【props、state、Lifecycle...】
  3. 虚拟dom,
  4. 组件渲染和diff,Lists and Keys

更多的学习react学习官网

redux

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。 惟一改变 state 的办法是触发 action,一个描述发生什么的对象。 为了描述 action 如何改变 state 树,你需要编写 reducers;
  1. 应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中,初始时由reducer初识态来创建
  2. 改变state的唯一方法就是触发dispatch一个action,
  3. 一个action是本质上一个对象,用来把最新的数据传到store的有效载荷
  4. Reducer就是把action这个有效载荷解析,并应用到store之中;

具体实践中:

  1. 书写reducer,来确定初始时的state
  2. 根据初始reducer来创建store,并使用store.subscribe来监听store变化时的操作
  3. 书写action,来承载每次修改store的变化
  4. 在交互等情况使用dispatch一个相应的action,
  5. reducer来响应action,并更新store,[store.subscribe监听函数将会被执行来驱动页面变化]
import { createStore } from 'redux';

/**
 * 这是一个 reducer,形式为 (state,action) => state 的纯函数。
 * 描述了 action 如何把 state 转变成下一个 state。
 *
 * state 的形式取决于你,可以是基本类型、数组、对象、
 * 甚至是 Immutable.js 生成的数据结构。惟一的要点是
 * 当 state 变化时需要返回全新的对象,而不是修改传入的参数。
 *
 * 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)
 * 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。
 */
function counter(state = 0,action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1;
  case 'DECREMENT':
    return state - 1;
  default:
    return state;
  }
}

// 创建 Redux store 来存放应用的状态。
// API 是 { subscribe,dispatch,getState }。
let store = createStore(counter);

// 可以手动订阅更新,也可以事件绑定到视图层。
store.subscribe(() =>
  console.log(store.getState())
);

// 改变内部 state 惟一方法是 dispatch 一个 action。
// action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1

异步redux

像 redux-thunk 或 redux-promise 这样支持异步的 middleware 都包装了 store 的 dispatch() 方法,以此来让你 dispatch 一些除了 action 以外的其他内容,例如:函数或者 Promise。

redux-react

Redux 官方提供的 React 绑定库。 具有高效且灵活的特性。

结合react来完善了下redux的使用,不需要我们每次都使用store.subscribe来监听store的变化,提供了新的接口:

<Provider store>
可以在最顶层将store传递至每个需要store的子组件

connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])
可以将一些state映射到某个组件,来驱动组件渲染

总结

react-redux-demo

需要webpack3以上

运行方式:

`npm install`  安装相关依赖
`webpack` 执行webpack来进行打包

在浏览器中打开目录下的/html/pages/home.html文件即可访问结果

➜  react-redux-demo git:(master) tree -I node_modules 
.
├── html
│ └── pages
│     └── home.html
├── package-lock.json
├── package.json
├── readMe.md
├── src
│ ├── dist
│ │ ├── css
│ │ │ └── home.css

│ │ ├── images
│ │ │ └── head.jpeg
│ │ └── js
│ │     └── home.js
│ ├── scripts
│ │ ├── common
│ │ └── pages
│ │     └── home
│ │         ├── actions
│ │         │ ├── data.js
│ │         │ └── index.js
│ │         ├── components
│ │         │ ├── app.js
│ │         │ ├── article
│ │         │ │ └── index.js
│ │         │ └── consults
│ │         │     └── index.js
│ │         ├── index.js
│ │         ├── reducers
│ │         │ ├── data.js
│ │         │ └── index.js
│ │         └── store
│ │             └── index.js
│ └── styles
│     ├── images
│     │ └── home
│     │     └── head.jpeg
│     ├── lib
│     │ └── base.scss
│     ├── module
│     └── pages
│         └── home.scss
└── webpack.config.js

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom