博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
shadow-cljs: JavaScript 依赖的实践
阅读量:6590 次
发布时间:2019-06-24

本文共 4634 字,大约阅读时间需要 15 分钟。

原文

原作者是 shadow-cljs 作者, 是一个面向 JavaScript 开发者友好的 ClojureScript 编译器.

之前关于 js 依赖的文章(, )里面, 我解释了为什么 shadow-cljs 当中采用了和 ClojureScript 默认的方案不同的做法. 简单回顾下:

  • cljsjs 或者 :foreign-libs 的写法难以扩张

  • 自定义的打包实际当中使用繁琐

  • Closure Compiler 目前对大部分的 npm 模块的处理不够可靠

  • shadow-cljs 自定义了一个 js bundler, 而移除了 :foreign-libs 的支持

安装 js 依赖

几乎所有的 npm 模块都会写一遍如何安装. 现在对于 shadow-cljs 来说也是适用的. 比如有个类库要你运行:

npm install the-thing

你照做就好. 不需要其他步骤了. 当然你喜欢的话可以用 yarn. 然后依赖就会被写进 package.json 文件用于管理. 如果没有 package.json 那就运行 npm init.

上面说到这些东西, 你可以用这个 来试用.

试用 js 依赖

大部分的 npm 模块也会写一下具体的代码表示怎样使用模块. "旧的" CommonJS 的写法是用 require 调用. 翻译到 ClojureScript 就是:

var react = require('react');
(ns my.app  (:require ["react" :as react]))

不管 "string" 参数的地方用了什么然后被 require 调用, 我们都是这样换成 ns :require. :as 的 alias 部分就随你定义. 有了这个之后, 它就像是其他的 cljs 的命名空间那样可以调用了:

(react/createElement "div" nil "helle world")

这跟以前 :foreign-libs 或者 CLJSJS 当中做的不一样, 以前比如引入了 thingns 然后要用 js/Thing(或者其他全局导出的变量)来使用代码. 现在可以用 ns 格式以及 :as 后面提供的名称. 需要的话还可以写 :refer:rename.

一些模块会暴露一个函数, 那你可以写 (:require ["thing" as thing]) 然后调用 (thing).

最近一些模块开始用 ES6 的 import 语法作为例子了. 这些代码除了一个 default 写法以外, 基本上在 ClojureScript 能做到一一对应. 比如说翻译下面的例子:

import defaultExport from "module-name";import * as name from "module-name";import { export } from "module-name";import { export as alias } from "module-name";import { export1 , export2 } from "module-name";import { export1 , export2 as alias2 , [...] } from "module-name";import defaultExport, { export [ , [...] ] } from "module-name";import defaultExport, * as name from "module-name";import "module-name";

到(包裹在 ns 里面的):

(:require ["module-name" :default defaultExport])(:require ["module-name" :as name])(:require ["module-name" :refer (export)])(:require ["module-name" :rename {export alias}])(:require ["module-name" :refer (export1) :rename {export2 alias2}])(:require ["module-name" :refer (export) :default defaultExport])(:require ["module-name" :as name :default defaultExport])(:require ["module-name"])

其中 :default 参数目前只在 shadow-cljs 里面支持, 但是你也可以帮助它进入到规范当中. 或者你也可以一直用 :as alias 然后调用 alias/default, 这样你觉得能个标准的 cljs 始终保持兼容的话. 我觉得吧, 对于某些模块来说啰嗦了点.

新的可能性

之前我们的使用打包之后的代码, 可能会包含我们用不到的代码. 某些模块也说明了一些办法可以只引入部分的模块, 这样最终构建的代码体积会小一些.

有个这样的例子:

// You can import any component you want as a named export from 'react-virtualized', egimport { Column, Table } from 'react-virtualized'// But if you only use a few react-virtualized components,// And you're concerned about increasing your application's bundle size,// You can directly import only the components you need, like so:import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer'import List from 'react-virtualized/dist/commonjs/List'

那么很容易翻译过去:

;; all(:require ["react-virtualized" :refer (Column Table)]);; one by one(:require ["react-virtualized/dist/commonjs/AutoSizer" :default virtual-auto-sizer])(:require ["react-virtualized/dist/commonjs/List" :default virtual-list])

查找 js 依赖

默认情况下 shadow-cljs 通过 npm 的方式引用查找所有 (:require ["thing" :as x]). 也就是说会查找 <project>/node_modules/thing/... 当中的代码. 为了对这个行为进行自定义, shadow-cljs 暴露了一个 :resolve 配置项, 你可以自己定义某些模块如何查找.

使用 CDN

比如说页面里的 React 从 CDN 上引用了. 这时候按说你可以用 js/React 了, 但是最好还是不要这样. 你应该是继续用 (:require ["react" :as react]), 同时在 shadow-cljs 里定义 react 怎样查找. 这个配置在 shadow-cljs.edn 文件里配置:

{:builds {:app  {:target :browser   ...   :js-options   {:resolve {"react" {:target :global                       :global "React"}}}}  :server  {:target :node-script   ...}}}

现在 :app 这个构建会使用全局的 React 实例, 而在 :server 这个构建当中会继续使用 react 的 npm 模块. 不需要额外折腾代码去完成需求.

重定向 require

某些模块提供多个 "dist" 文件, 然后可能默认的那个刚好是在 shadow-cljs 里有问题的. 一个明显的例子就是 d3. 他们默认的 "main" 指向 build/d3.node.js, 这个不是在浏览器里面用的版本. 他们的 ES6 代码还触发了 里的一个 bug, 所以我们不能用. 这样的话我们就重定向到其他的引用去:

{:resolve {"d3" {:target :npm                 :require "d3/build/d3.js"}}}

你也可以直接就写 (:require ["d3/build/d3.js" :as d3]), 如果你只关心浏览器当中的使用的话.

使用本地文件

你还可以用 :resolve 来直接映射到一个项目中的本地文件:

{:resolve {"my-thing" {:target :file                       :file "path/to/file.js"}}}

这里的 :file 总是相对于项目根路径. 这个文件里可以用 require 或者 import/export, 这些随后都会被处理好的.

迁移 cljsjs.*

很多 cljs 类库还在用 CLJSJS 包, 它们在 shadow-cljs 里不能正常使用了, 因为 :foreign-libs 不再支持. 我提供了一个清晰的迁移路线, 只需要增加一个 shim 文件把 cljsjs.thing 映射回到原始的 npm 模块, 然后把全局变量暴露出去.

比如 react 需要一个这样的文件:

(ns cljsjs.react  (:require ["react" :as react]            ["create-react-class" :as crc]))(js/goog.object.set react "createClass" crc)(js/goog.exportSymbol "React" react)

因为这样的话每个人手动处理会麻烦, 所以我提供了 这个类库来提供这个功能. 虽然不会包含每一个模块, 但是我会持续添加. 欢迎来帮忙贡献模块.

不过它仅仅提供 shim 文件. 你还是需要用 npm install 安装真实的模块.

其他功能不能用怎么办?

JavaScript 社区变化很快, 并不是每个人都一样地写代码, 都一样地分发代码, 有些东西是 shadow-cljs 不能自动处理或者需要自定义 :resolve 配置的. 可能是会遇到 bug, 毕竟都是新东西.

遇到任何模块不能按照预期地使用, 请. 在 很容易找到我.

关于这篇文章的讨论请移步 .

转载地址:http://cgkio.baihongyu.com/

你可能感兴趣的文章
洛谷P1069 细胞分裂 数学
查看>>
JAVA中的编码分析
查看>>
查看源代码Source not found及在eclipse中配置jdk的src.zip源代码
查看>>
document.all用法
查看>>
uniGUI试用笔记(二)
查看>>
HOG特征-理解篇
查看>>
Microsoft.AlphaImageLoader滤镜解说
查看>>
extjs_02_grid(显示本地数据,显示跨域数据)
查看>>
超过响应缓冲区限制
查看>>
ubuntu 下安装 matplotlib
查看>>
webservice的几个简单概念
查看>>
underscore 1.7.0 api
查看>>
C# CheckedListBox控件的使用方法
查看>>
spring Transaction Management --官方
查看>>
iOS开发-清理缓存功能的实现
查看>>
IS_ERR、PTR_ERR、ERR_PTR
查看>>
html5 canvas 奇怪的形状垂直渐变
查看>>
mac java环境
查看>>
lamp 一键安装
查看>>
SQL Server 2008 收缩日志(log)文件
查看>>