| OLD | NEW |
| (Empty) |
| 1 <ol class="toc"> | |
| 2 <li><a href="#a-name-and-a-number">A name and a number</a></li> | |
| 3 <li><a href="#shared-dependencies-and-unshared-libraries">Shared dependencies
and unshared libraries</a></li> | |
| 4 <li><a href="#version-lock">Version lock</a></li> | |
| 5 <li><a href="#version-constraints">Version constraints</a></li> | |
| 6 <li><a href="#semantic-versions">Semantic versions</a></li> | |
| 7 <li><a href="#constraint-solving">Constraint solving</a></li> | |
| 8 <li><a href="#constraint-context">Constraint context</a></li> | |
| 9 <li><a href="#lockfiles">Lockfiles</a></li> | |
| 10 <li><a href="#when-things-go-wrong">When things go wrong</a></li> | |
| 11 <li><a href="#summary">Summary</a></li> | |
| 12 </ol> | |
| 13 | |
| 14 <p>One of pub’s main jobs is helping you work with versioning. Here, I&rsq
uo;ll | |
| 15 explain a bit about the history of versioning and pub’s approach to it. | |
| 16 Consider this to be advanced information. If you want a better picture of <em>wh
y</em> | |
| 17 pub was designed the way it was, read on. If you just want to <em>use</em> pub,
the | |
| 18 <a href="index.html">other docs</a> will serve you better.</p> | |
| 19 | |
| 20 <p>Modern software development, especially web development, leans heavily on | |
| 21 reusing lots and lots of existing code. That includes code <em>you</em> wrote in
the | |
| 22 past, but also stuff from third-parties, everything from big frameworks to tiny | |
| 23 little utility libraries. It’s not uncommon for an application to depend o
n | |
| 24 dozens of different packages and libraries.</p> | |
| 25 | |
| 26 <p>It’s hard to understate how awesome this is. When you see stories of ti
ny web | |
| 27 startups building a site in a few weeks that gets millions of users, the | |
| 28 only reason they can pull that off is because the open source community has | |
| 29 laid a feast of software at their feet.</p> | |
| 30 | |
| 31 <p>But there’s still no such thing as a free lunch. There’s a challe
nge to code | |
| 32 reuse, especially reusing code you don’t maintain. When your app uses tons
of | |
| 33 code being developed by other people, what happens when they change it? They | |
| 34 don’t want to break your app, and you certainly don’t either.</p> | |
| 35 | |
| 36 <h2 id="a-name-and-a-number">A name and a number</h2> | |
| 37 | |
| 38 <p>We solve this by <em>versioning</em>. When you depend on some piece of outsid
e code, | |
| 39 you don’t just say “My app uses <code>widgets</code>.” You say
, “My app uses | |
| 40 <code>widgets 2.0.5</code>.” That combination of name and version number u
niquely | |
| 41 identifies an <em>immutable</em> chunk of code. The people hacking on <code>widg
ets</code> can | |
| 42 make all of the changes they want, but they promise to not touch any already | |
| 43 released versions. They can put out <code>2.0.6</code> or <code>3.0.0</code> and
it won’t affect you | |
| 44 one whit because the version you use is unchanged.</p> | |
| 45 | |
| 46 <p>When you <em>do</em> want to get those changes, you can always point your app
to a | |
| 47 newer version of <code>widgets</code> and you don’t have to coordinate wit
h those | |
| 48 developers to do it. So, problem solved, right?</p> | |
| 49 | |
| 50 <h2 id="shared-dependencies-and-unshared-libraries">Shared dependencies and unsh
ared libraries</h2> | |
| 51 | |
| 52 <p>Well, no. Depending on specific versions works fine when your dependency <em>
graph</em> | |
| 53 is really just a dependency <em>tree</em>. If your app depends on a bunch of stu
ff, and | |
| 54 those things in turn have their own dependencies and so on, that all works fine | |
| 55 as long as none of those dependencies <em>overlap</em>.</p> | |
| 56 | |
| 57 <p>But let’s consider an example:</p> | |
| 58 | |
| 59 <pre><code> myapp | |
| 60 / \ | |
| 61 / \ | |
| 62 widgets templates | |
| 63 \ / | |
| 64 \ / | |
| 65 collections | |
| 66 </code></pre> | |
| 67 | |
| 68 <p>So your app uses <code>widgets</code> and <code>templates</code>, and <em>bot
h</em> of those use | |
| 69 <code>collections</code>. This is called a <strong>shared dependency</strong>. N
ow what happens when | |
| 70 <code>widgets</code> wants to use <code>collections 2.3.5</code> and <code>templ
ates</code> wants | |
| 71 <code>collections 2.3.7</code>? What if they don’t agree on a version?</p> | |
| 72 | |
| 73 <p>One option is to just let the app use both | |
| 74 versions of <code>collections</code>. It will have two copies of the library at
different | |
| 75 versions and <code>widgets</code> and <code>templates</code> will each get the o
ne they want.</p> | |
| 76 | |
| 77 <p>This is what <a href="https://npmjs.org/">npm</a> does for node.js. Would it
work for Dart? Consider this | |
| 78 scenario:</p> | |
| 79 | |
| 80 <ol> | |
| 81 <li><code>collections</code> defines some <code>Dictionary</code> class.</li> | |
| 82 <li><code>widgets</code> gets an instance of it from its copy of <code>collect
ions</code> (<code>2.3.5</code>). | |
| 83 It then passes it up to <code>myapp</code>.</li> | |
| 84 <li><code>myapp</code> sends the dictionary over to <code>templates</code>.</l
i> | |
| 85 <li>That in turn sends it down to <em>its</em> version of <code>collections</c
ode> (<code>2.3.7</code>).</li> | |
| 86 <li>The method that takes it has a <code>Dictionary</code> type annotation for
that object.</li> | |
| 87 </ol> | |
| 88 | |
| 89 <p>As far as Dart is concerned, <code>collections 2.3.5</code> and <code>collect
ions 2.3.7</code> are | |
| 90 entirely unrelated libraries. If you take an instance of class <code>Dictionary<
/code> from | |
| 91 one and pass it to a method in the other, that’s a completely different | |
| 92 <code>Dictionary</code> type. That means it will fail to match a <code>Dictionar
y</code> type | |
| 93 annotation in the receiving library. Oops.</p> | |
| 94 | |
| 95 <p>Because of this (and because of the headaches of trying to debug an app that | |
| 96 has multiple versions of things with the same name), we’ve decided npm&rsq
uo;s model | |
| 97 isn’t a good fit.</p> | |
| 98 | |
| 99 <h2 id="version-lock">Version lock</h2> | |
| 100 | |
| 101 <p>Instead, when you depend on a package, your app will only use a single copy o
f | |
| 102 that package. When you have a shared dependency, everything that depends on it | |
| 103 has to agree on which version to use. If they don’t, you get an error.</p> | |
| 104 | |
| 105 <p>That doesn’t actually solve your problem though. When you <em>do</em> g
et that error, | |
| 106 you need to be able to resolve it. So let’s say you’ve gotten yourse
lf into | |
| 107 that situation in the above example. You want to use <code>widgets</code> and <c
ode>templates</code>, | |
| 108 but they are using different versions of <code>collections</code>. What do you d
o?</p> | |
| 109 | |
| 110 <p>The answer is to try to upgrade one of those. <code>templates</code> wants | |
| 111 <code>collections 2.3.7</code>. Is there a later version of <code>widgets</code>
that you can upgrade | |
| 112 to that works with that version?</p> | |
| 113 | |
| 114 <p>In many cases, the answer will be “no”. Look at it from the persp
ective of the | |
| 115 people developing <code>widgets</code>. They want to put out a new version with
new changes | |
| 116 to <em>their</em> code, and they want as many people to be able to upgrade to it
it as | |
| 117 possible. If they stick to their <em>current</em> version of <code>collections</
code> then anyone | |
| 118 who is using the current version <code>widgets</code> will be able to drop in th
is new one | |
| 119 too.</p> | |
| 120 | |
| 121 <p>If they were to upgrade <em>their</em> dependency on <code>collections</code>
then everyone who | |
| 122 upgrades <code>widgets</code> would have to as well, <em>whether they want to or
not.</em> That’s | |
| 123 painful, so you end up with a disincentive to upgrade dependencies. That’s | |
| 124 called <strong>version lock</strong>: everyone wants to move their dependencies
forward, but | |
| 125 no one can take the first step because it forces everyone else to as well.</p> | |
| 126 | |
| 127 <h2 id="version-constraints">Version constraints</h2> | |
| 128 | |
| 129 <p>To solve version lock, we loosen the constraints that packages place on their | |
| 130 dependencies. If <code>widgets</code> and <code>templates</code> can both indica
te a <em>range</em> of | |
| 131 versions for <code>collections</code> that they will work with, then that gives
us enough | |
| 132 wiggle room to move our dependencies forward to newer versions. As long as there | |
| 133 is overlap in their ranges, we can still find a single version that makes them | |
| 134 both happy.</p> | |
| 135 | |
| 136 <p>This is the model that <a href="http://gembundler.com/">bundler</a> follows,
and is pub’s | |
| 137 model too. When you add a dependency in your pubspec, you can specify a <em>rang
e</em> | |
| 138 of versions that you can accept. If the pubspec for <code>widgets</code> looked
like this:</p> | |
| 139 | |
| 140 <div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">depe
ndencies</span><span class="p-Indicator">:</span> | |
| 141 <span class="l-Scalar-Plain">collections</span><span class="p-Indicator">:</sp
an> <span class="s">'>=2.3.5</span><span class="nv"> </span><span class="
s"><2.4.0'</span> | |
| 142 </code></pre></div> | |
| 143 | |
| 144 <p>Then we could pick version <code>2.3.7</code> for <code>collections</code> an
d then both <code>widgets</code> | |
| 145 and <code>templates</code> have their constraints satisfied by a single concrete
version.</p> | |
| 146 | |
| 147 <h2 id="semantic-versions">Semantic versions</h2> | |
| 148 | |
| 149 <p>When you add a dependency to your package, you’ll sometimes want to spe
cify a | |
| 150 range of versions to allow. How do you know what range to pick? You need to | |
| 151 forward compatible, so ideally the range encompasses future versions that | |
| 152 haven’t been released yet. But how do you know your package is going to wo
rk | |
| 153 with some new version that doesn’t even exist yet?</p> | |
| 154 | |
| 155 <p>To solve that, you need to agree on what a version number <em>means</em>. Ima
gine that | |
| 156 the developers of a package you depend on say, “If we make any backwards | |
| 157 incompatible change, then we promise to increment the major version number.&rdqu
o; | |
| 158 If you trust them, then if you know your package works with <code>2.5.7</code> o
f theirs, | |
| 159 you can rely on it working all the way up to <code>3.0.0</code>. So you can set
your range | |
| 160 like:</p> | |
| 161 | |
| 162 <div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">depe
ndencies</span><span class="p-Indicator">:</span> | |
| 163 <span class="l-Scalar-Plain">collections</span><span class="p-Indicator">:</sp
an> <span class="s">'>=2.3.5</span><span class="nv"> </span><span class="
s"><3.0.0'</span> | |
| 164 </code></pre></div> | |
| 165 | |
| 166 <p>To make this work, then, we need to come up with that set of promises. | |
| 167 Fortunately, other smart people have done the work of figuring this all out and | |
| 168 named it <a href="http://semver.org/"><em>semantic versioning</em></a>.</p> | |
| 169 | |
| 170 <p>That describes the format of a version number, and the exact API behavioral | |
| 171 differences when you increment to a later version number. Pub requires versions | |
| 172 to be formatted that way, and to play well with the pub community, your package | |
| 173 should follow the semantics it specifies. You should assume that the packages | |
| 174 you depend on also follow it. (And if you find out they don’t, let their | |
| 175 authors know!)</p> | |
| 176 | |
| 177 <p>We’ve got almost all of the pieces we need to deal with versioning and
API | |
| 178 evolution now. Let’s see how they play together and what pub does.</p> | |
| 179 | |
| 180 <h2 id="constraint-solving">Constraint solving</h2> | |
| 181 | |
| 182 <p>When you define your package, you list its | |
| 183 <a href="glossary.html#immediate-dependency"><strong>immediate dependencies</str
ong></a>—the | |
| 184 packages it itself uses. For each one, you specify the range of versions it | |
| 185 allows. Each of those dependent packages may in turn have their own | |
| 186 dependencies (called | |
| 187 <a href="glossary.html#transitive-dependency"><strong>transitive dependencies</s
trong></a>. Pub will | |
| 188 traverse these and build up the entire deep dependency graph for your app.</p> | |
| 189 | |
| 190 <p>For each package in the graph, pub looks at everything that depends on it. It | |
| 191 gathers together all of their version constraints and tries to simultaneously | |
| 192 solve them. (Basically, it intersects their ranges.) Then it looks at the | |
| 193 actual versions that have been released for that package and selects the best | |
| 194 (most recent) one that meets all of those constraints.</p> | |
| 195 | |
| 196 <p>For example, let’s say our dependency graph contains <code>collections<
/code>, and three | |
| 197 packages depend on it. Their version constraints are:</p> | |
| 198 | |
| 199 <pre><code>>=1.7.0 | |
| 200 >=1.4.0 <2.0.0 | |
| 201 <1.9.0 | |
| 202 </code></pre> | |
| 203 | |
| 204 <p>The developers of <code>collections</code> have released these versions of it
:</p> | |
| 205 | |
| 206 <pre><code>1.7.0 | |
| 207 1.7.1 | |
| 208 1.8.0 | |
| 209 1.8.1 | |
| 210 1.8.2 | |
| 211 1.9.0 | |
| 212 </code></pre> | |
| 213 | |
| 214 <p>The highest version number that fits in all of those ranges is <code>1.8.2</c
ode>, so pub | |
| 215 picks that. That means your app <em>and every package your app uses</em> will al
l use | |
| 216 <code>collections 1.8.2</code>.</p> | |
| 217 | |
| 218 <h2 id="constraint-context">Constraint context</h2> | |
| 219 | |
| 220 <p>The fact that selecting a package version takes into account <em>every</em> p
ackage | |
| 221 that depends on it has an important consequence: <em>the specific version that | |
| 222 will be selected for a package is a global property of the app using that | |
| 223 package.</em></p> | |
| 224 | |
| 225 <p>I’ll walk through an example so you can see what this means. Let’
s say we have | |
| 226 two apps. Here are their pubspecs:</p> | |
| 227 | |
| 228 <div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name
</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">my_app</s
pan> | |
| 229 <span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</spa
n> | |
| 230 <span class="l-Scalar-Plain">widgets</span><span class="p-Indicator">:</span> | |
| 231 </code></pre></div> | |
| 232 | |
| 233 <div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name
</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">other_app
</span> | |
| 234 <span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</spa
n> | |
| 235 <span class="l-Scalar-Plain">widgets</span><span class="p-Indicator">:</span> | |
| 236 <span class="l-Scalar-Plain">collections</span><span class="p-Indicator">:</sp
an> <span class="s">'<1.5.0'</span> | |
| 237 </code></pre></div> | |
| 238 | |
| 239 <p>They both depend on <code>widgets</code>, whose pubspec is:</p> | |
| 240 | |
| 241 <div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name
</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">widgets</
span> | |
| 242 <span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</spa
n> | |
| 243 <span class="l-Scalar-Plain">collections</span><span class="p-Indicator">:</sp
an> <span class="s">'>=1.0.0</span><span class="nv"> </span><span class="
s"><2.0.0'</span> | |
| 244 </code></pre></div> | |
| 245 | |
| 246 <p>The <code>other_app</code> package uses depends directly on <code>collections
</code> itself. The | |
| 247 interesting part is that it happens to have a different version constraint on | |
| 248 it than <code>widgets</code> does.</p> | |
| 249 | |
| 250 <p>What this means is that you can’t just look at the <code>widgets</code>
package in | |
| 251 isolation to figure out what version of <code>collections</code> it will use. It
depends | |
| 252 on the context. In <code>my_app</code>, <code>widgets</code> will be using <code
>collections 1.9.9</code>. But | |
| 253 in <code>other_app</code>, <code>widgets</code> will get saddled with <code>coll
ections 1.4.9</code> because of | |
| 254 the <em>other</em> constraint that <code>otherapp</code> places on it.</p> | |
| 255 | |
| 256 <p>This is why each app gets its own “packages” directory: The concr
ete version | |
| 257 selected for each package depends on the entire dependency graph of the | |
| 258 containing app.</p> | |
| 259 | |
| 260 <h2 id="lockfiles">Lockfiles</h2> | |
| 261 | |
| 262 <p>So once pub has solved your app’s version constraints, then what? The e
nd | |
| 263 result is a complete list of every package that your app depends on either | |
| 264 directly or indirectly and the best version of that package that will work with | |
| 265 your app’s constraints.</p> | |
| 266 | |
| 267 <p>Pub takes that and writes it out to a <strong>lockfile</strong> in your app&r
squo;s directory | |
| 268 called <code>pubspec.lock</code>. When pub builds the “packages” dir
ectory your app, it | |
| 269 uses the lockfile to know what versions of each package to pull in. (And if | |
| 270 you’re curious to see what versions it selected, you can read the lockfile
to | |
| 271 find out.)</p> | |
| 272 | |
| 273 <p>The next important thing pub does is it <em>stops touching the lockfile</em>.
Once | |
| 274 you’ve got a lockfile for your app, pub won’t mess with it until you
tell it to. | |
| 275 This is important. It means you won’t spontanteously start using new versi
ons | |
| 276 of random packages in your app without intending to. Once your app is locked, | |
| 277 it stays locked until you manually tell it to update the lockfile.</p> | |
| 278 | |
| 279 <p>If your package is for an app, you take your lockfile <em>check that bad boy | |
| 280 into your source control system!</em> That way, everyone on your team will be us
ing | |
| 281 the exact same versions of every dependency when they hack on your app. You&rsqu
o;ll | |
| 282 also use this when you deploy your app so you can ensure that your production | |
| 283 servers are using the exact same packages that you’re developing with.</p> | |
| 284 | |
| 285 <h2 id="when-things-go-wrong">When things go wrong</h2> | |
| 286 | |
| 287 <p>Of course, all of this presumes that your dependency graph is perfect and | |
| 288 flawless. Oh, to be so fortunate. Even with version ranges and pub’s const
raint | |
| 289 solving and semantic versioning, you can never be entirely spared from the | |
| 290 dangers of version hell.</p> | |
| 291 | |
| 292 <p>There are a couple of problems you can run into:</p> | |
| 293 | |
| 294 <h3 id="you-can-have-disjoint-constraints">You can have disjoint constraints</h3
> | |
| 295 | |
| 296 <p>Lets say your app uses <code>widgets</code> and | |
| 297 <code>templates</code> and both use <code>collections</code>. But <code>widgets<
/code> asks for a version | |
| 298 of it between <code>1.0.0</code> and <code>2.0.0</code> and <code>templates</cod
e> wants something | |
| 299 between <code>3.0.0</code> and <code>4.0.0</code>. Those ranges don’t even
overlap. There’s no | |
| 300 possible version that would work.</p> | |
| 301 | |
| 302 <h3 id="you-can-have-ranges-that-dont-contain-a-released-version">You can have r
anges that don’t contain a released version</h3> | |
| 303 | |
| 304 <p>Let’s say after | |
| 305 putting all of the constraints on a shared dependency together, you’re | |
| 306 left with the narrow range of <code>>=1.2.4 <1.2.6</code>. It’s not
an empty range. | |
| 307 If there was a version <code>1.2.4</code> of the dependency, you’d be gold
en. But maybe | |
| 308 they never released that and instead when straight from <code>1.2.3</code> to <c
ode>1.3.0</code>. | |
| 309 You’ve got a range but nothing exists inside it.</p> | |
| 310 | |
| 311 <h3 id="you-can-have-an-unstable-graph">You can have an unstable graph</h3> | |
| 312 | |
| 313 <p>This is, by far, the hairiest part of | |
| 314 pub’s version solving process. I’ve described the process as “
build up the | |
| 315 dependency graph and then solve all of the constraints and pick versions”. | |
| 316 But it doesn’t actually work that way. How could you build up the <em>whol
e</em> | |
| 317 dependency graph before you’ve picked <em>any</em> versions? <em>The pubsp
ecs | |
| 318 themselves are version-specific</em>. Different versions of the same package | |
| 319 may have different sets of dependencies.</p> | |
| 320 | |
| 321 <p>As you’re selecting versions of packages, they are changing the shape o
f | |
| 322 the dependency graph itself. As the graph changes, that may change | |
| 323 constraints, which can cause you to select different versions, and then you | |
| 324 go right back around in a circle.</p> | |
| 325 | |
| 326 <p>Sometimes this process never settles down into a stable solution. Gaze into | |
| 327 the abyss:</p> | |
| 328 | |
| 329 <div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name
</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">my_app</s
pan> | |
| 330 <span class="l-Scalar-Plain">version</span><span class="p-Indicator">:</span> <s
pan class="l-Scalar-Plain">0.0.0</span> | |
| 331 <span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</spa
n> | |
| 332 <span class="l-Scalar-Plain">yin</span><span class="p-Indicator">:</span> <spa
n class="s">'>=1.0.0'</span> | |
| 333 </code></pre></div> | |
| 334 | |
| 335 <div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name
</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">yin</span
> | |
| 336 <span class="l-Scalar-Plain">version</span><span class="p-Indicator">:</span> <s
pan class="l-Scalar-Plain">1.0.0</span> | |
| 337 <span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</spa
n> | |
| 338 </code></pre></div> | |
| 339 | |
| 340 <div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name
</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">yin</span
> | |
| 341 <span class="l-Scalar-Plain">version</span><span class="p-Indicator">:</span> <s
pan class="l-Scalar-Plain">2.0.0</span> | |
| 342 <span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</spa
n> | |
| 343 <span class="l-Scalar-Plain">yang</span><span class="p-Indicator">:</span> <sp
an class="s">'1.0.0'</span> | |
| 344 </code></pre></div> | |
| 345 | |
| 346 <div class="highlight"><pre><code class="yaml"><span class="l-Scalar-Plain">name
</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">yang</spa
n> | |
| 347 <span class="l-Scalar-Plain">version</span><span class="p-Indicator">:</span> <s
pan class="l-Scalar-Plain">1.0.0</span> | |
| 348 <span class="l-Scalar-Plain">dependencies</span><span class="p-Indicator">:</spa
n> | |
| 349 <span class="l-Scalar-Plain">yin</span><span class="p-Indicator">:</span> <spa
n class="s">'1.0.0'</span> | |
| 350 </code></pre></div> | |
| 351 | |
| 352 <p>In all of these cases, there is no set of concrete versions that will work fo
r | |
| 353 your app, and when this happens pub will report an error and tell you what&rsquo
;s | |
| 354 going on. It definitely will not try to leave you in some weird state where you | |
| 355 think things can work but won’t.</p> | |
| 356 | |
| 357 <h2 id="summary">Summary</h2> | |
| 358 | |
| 359 <p>Wow, that’s a lot to get through. Here’s the important bits:</p> | |
| 360 | |
| 361 <ul> | |
| 362 <li>Code reuse is great, but in order to let developers move quickly, packages | |
| 363 need to be able to evolve independently.</li> | |
| 364 <li>Versioning is how you enable that. But depending on single concrete versio
ns | |
| 365 is too precise and with shared dependencies leads to version lock.</li> | |
| 366 <li>To cope with that, you depend on <em>ranges</em> of versions. Pub will the
n walk | |
| 367 your dependency graph and pick the best versions for you. If it can’t, it | |
| 368 tells you.</li> | |
| 369 <li>Once your app has a solid set of versions for its dependencies, that gets | |
| 370 pinned down in a <em>lockfile</em>. That ensures that every machine your app is | |
| 371 on is using the same versions of all of its dependencies.</li> | |
| 372 </ul> | |
| OLD | NEW |